我正在尝试从 Access 数据库中读取表,然后将该表中的数据排序到多个文本文件中。关键是要写入的文件名取决于每条记录中的值。这是我正式的第一个 C# 应用程序,所以你可以认为我是“绿色的”。我还应该提到,我正在使用 Access 数据库,直到我可以敲定代码,最终它将从具有数百万条记录的 SQL 服务器中提取。
我现在有代码工作,但问题是有大量的文件打开/关闭操作。我只想打开每个文件一次进行写入,因为它将这些文件写入网络驱动器。这本质上是在服务器上运行的胶水应用程序 - 所以也有一些其他限制 - 我无法保存到本地驱动器然后复制到网络。我无法在拉取之前对查询进行排序。我不能在运行时对服务器资源产生不利影响。
可能最好的方法是使用哈希表。检查文件是否已经打开,如果没有,打开它并将文件句柄保存在哈希表中。然后在完成后立即将它们全部关闭。但是我找不到如何同时使用多个 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
}