- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试从 Access 数据库中读入一个表,然后将该表中的数据分类到多个文本文件中。关键是要写入的文件名取决于每个记录中的值。这是我正式的第一个 C# 应用程序,因此您可以认为我是“绿色”。我还应该提到,我正在处理 Access 数据库,直到我可以敲定代码为止,最终它将从具有数百万条记录的 SQL 服务器中提取。
我现在可以使用代码,但问题是有大量的文件打开/关闭操作。我只想打开每个文件一次进行写入,因为它将把这些文件写入网络驱动器。这本质上是一个在服务器上运行的胶水应用程序——所以也有一些其他限制——我不能保存到本地驱动器然后复制到网络。我无法在拉取之前对查询进行排序。我不能在运行时对服务器资源产生不利影响。
可能最好的方法是使用哈希表。检查文件是否被打开,如果没有打开,将文件句柄保存到Hash Table中。然后在完成后立即关闭它们。但是我找不到如何同时使用多个 StreamWriter 对象的示例。
我希望相对容易地找到这个问题的答案,但我似乎找不到他的解决方案。我怀疑 StreamWriter 是为此使用的错误类。
我能找到的最近的问题来自 CodeProject page .在那个页面上,他们说保持文件手打开的做法是不好的,应该避免,但是该页面没有解释原因,也没有提供示例替代方案。有人建议将整个数据集加载到内存中,然后对其进行操作,但这对我来说不是一个选项,因为表中的数据太多。
这是我目前所拥有的。
String strConnection;
String strQuery;
String strPunchFileNameTemplate;
// Define our Variables
strConnection = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=ClockData.accdb";
strQuery = @"SELECT * FROM ClockPunches";
strPunchFileNameTemplate = @"C:\PUNCHES\%READER%.TXT";
// OleDbConnection implements iDisposable interface, so we must scope out its usage.
// Set up Connection to our data source
using (OleDbConnection ConnObj = new OleDbConnection(strConnection)) {
// Create a Command with our Query String
OleDbCommand CmdObj = new OleDbCommand(strQuery,ConnObj);
// Open our Connection
ConnObj.Open();
// OledbDataReader implements iDisposable interface, so we must scope out its usage.
// Execute our Reader
using (OleDbDataReader ReaderObj = CmdObj.ExecuteReader(CommandBehavior.KeyInfo)) {
// Load the source table's schema into memory (a DataTable object)
DataTable TableObj = ReaderObj.GetSchemaTable();
// Parse through each record in the Reader Object
while(ReaderObj.Read()) {
// Extract PunchTime, CardNumber, and Device to separate variables
DateTime dtTime = ReaderObj.GetDateTime(ReaderObj.GetOrdinal("PunchTime"));
Int16 intID = ReaderObj.GetInt16(ReaderObj.GetOrdinal("CardNumber"));
String strReader = ReaderObj.GetString(ReaderObj.GetOrdinal("Device"));
// Translate the device name into a designated filename (external function)
strReader = GetDeviceFileName(strReader);
// Put our dynamic filename into the path template
String pathStr = strPunchFileNameTemplate.Replace("%READER%",strReader);
// Check to see if the file exists. New files need an import Header
Boolean FileExistedBool = File.Exists(pathStr);
// StreamWrite implements iDisposable interface, so we must scope out its usage.
// Create a Text File for each Device, Append if it exists
using (StreamWriter outSR = new StreamWriter(pathStr, true)) {
// Write our Header if required
if (FileExistedBool == false) {
outSR.WriteLine("EXAMPLE FILE HEADER");
}
// Set up our string we wish to write to the file
String outputStr = dtTime.ToString("MM-dd-yyyy HH:mm:ss") + " " + intID.ToString("000000");
// Write the String
outSR.WriteLine(outputStr);
// End of StreamWriter Scope - should automatically close
}
}
// End of OleDbDataREader Scope - should automatically close
}
// End of OleDbConnection Scope - should automatically close
}
最佳答案
这是您自己遇到的一个非常有趣的问题。
缓存文件处理程序的问题是大量的文件处理程序会耗尽系统资源,使程序和窗口性能不佳。
如果数据库中的设备数量不是太多(少于 100),我认为缓存句柄是安全的。
或者,您可以缓存一百万条记录,将它们分发到不同的设备并保存一些记录,然后读取更多记录。
您可以像这样将记录放入字典中:
class PunchInfo
{
public PunchInfo(DateTime time, int id)
{
Id = id;
Time = time;
}
public DateTime Time;
public int Id;
}
Dictionary<string, List<PunchInfo>> Devices;
int Count = 0;
const int Limit = 1000000;
const int LowerLimit = 90 * Limit / 100;
void SaveRecord(string device, int id, DateTime time)
{
PunchInfo info = new PunchInfo(time, id);
List<PunchInfo> list;
if (!Devices.TryGetValue(device, out list))
{
list = new List<PunchInfo>();
Devices.Add(device, list);
}
list.Add(info);
Count++;
if (Count >= Limit)
{
List<string> writeDevices = new List<string>();
foreach(KeyValuePair<string, List<PunchInfo>> item in Devices)
{
writeDevices.Add(item.Key);
Count -= item.Value.Count;
if (Count < LowerLimit) break;
}
foreach(string device in writeDevices)
{
List<PunchInfo> list = Devices[device];
Devices.Remove(device);
SaveDevices(device, list);
}
}
}
void SaveAllDevices()
{
foreach(KeyValuePair<string, List<PunchInfo>> item in Devices)
SaveDevices(item.Key, item.Value);
Devices.Clear();
}
这样您就可以避免打开和关闭文件并打开大量文件。
100 万条记录占用 20 MB 内存,您可以轻松地将其增加到 1000 万条记录而不会出现问题。
关于C# 写入多个文件而无需不断关闭/重新打开流。流作家?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15509597/
安装并修复我的 VS2015 实例后,我仍然无法让智能感知(服务器端)在我的 MVC View 中工作。当我在 session 中第一次打开 .cshtml 文件并找到 Activitylog 文件时
我是一名优秀的程序员,十分优秀!