OLEDB 的 Jet 驱动程序会在打开的 OleDbDataReader 时锁定平面文件。要验证这一点,请查看下面代码示例中的 VerifyFileLockedByOleDB 方法。请注意,只有一个开放的 OleDbConnection 是不够的——您必须有一个开放的阅读器。
也就是说,您上面发布的代码并没有保持打开的连接,因为它使用OleDbDataAdapter.Fill() 快速连接到数据源,吸出所有数据,然后断开连接。阅读器永远不会打开。该文件仅在Fill() 运行的(短)时间内被锁定。
此外,即使您自己打开阅读器并将其传递给DataTable.Load(),该方法也会在完成后为您关闭 DataReader,这意味着文件被解锁。
因此,如果您确实想保持文件锁定并仍然使用 DataTable,则需要从 IDataReader 手动填充数据表(模式和行!),而不是依赖 DataAdapter.Fill() 或 DataTable。加载()。
无论如何,这是一个代码示例,它显示:
- 您的原始代码
- 一个不起作用的示例,因为 DataTable.Load() 将关闭 DataReader 并解锁文件
- 另一种方法,通过使用 DataReader 而不是使用 DataTable 在行级别操作,在您处理数据时保持文件锁定
更新: 看起来保持 DataReader 打开会阻止同一个进程打开文件,但另一个进程(例如 Excel)可以打开(并写入!)文件。去搞清楚。无论如何,在这一点上,我建议,如果您真的想保持文件锁定,请考虑使用除 OLEDB 之外的其他东西,您可以更精细地控制文件的打开和关闭方式(以及何时!)。我建议来自http://www.codeproject.com/KB/database/CsvReader.aspx 的 CSV 阅读器,它经过充分测试且速度很快,但会为您提供源代码,因此如果您需要更改文件锁定/打开/关闭,您可以这样做。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Data;
using System.IO;
namespace TextFileLocking
{
class Program
{
private static DataTable OpenCSVasDB(string fullFileName)
{
string file = Path.GetFileName(fullFileName);
string dir = Path.GetDirectoryName(fullFileName);
string cStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=\"" + dir + "\\\";"
+ "Extended Properties=\"text;HDR=Yes;FMT=Delimited\";";
string sqlStr = "SELECT * FROM [" + file + "]";
OleDbDataAdapter da;
DataTable dt = new DataTable();
try
{
da = new OleDbDataAdapter(sqlStr, cStr);
da.Fill(dt);
}
catch { dt = null; }
return dt;
}
private static DataTable OpenCSVasDBWithLockWontWork(string fullFileName, out OleDbDataReader reader)
{
string file = Path.GetFileName(fullFileName);
string dir = Path.GetDirectoryName(fullFileName);
string cStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=\"" + dir + "\\\";"
+ "Extended Properties=\"text;HDR=Yes;FMT=Delimited\";";
string sqlStr = "SELECT * FROM [" + file + "]";
OleDbConnection openConnection = new OleDbConnection(cStr);
reader = null;
DataTable dt = new DataTable();
try
{
openConnection.Open();
OleDbCommand cmd = new OleDbCommand(sqlStr, openConnection);
reader = cmd.ExecuteReader();
dt.Load (reader); // this will close the reader and unlock the file!
return dt;
}
catch
{
return null;
}
}
private static void OpenCSVasDBWithLock(string fullFileName, Action<IDataReader> dataRowProcessor)
{
string file = Path.GetFileName(fullFileName);
string dir = Path.GetDirectoryName(fullFileName);
string cStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=\"" + dir + "\\\";"
+ "Extended Properties=\"text;HDR=Yes;FMT=Delimited\";";
string sqlStr = "SELECT * FROM [" + file + "]";
using (OleDbConnection conn = new OleDbConnection(cStr))
{
OleDbCommand cmd = new OleDbCommand(sqlStr, conn);
conn.Open();
using (OleDbDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
dataRowProcessor(reader);
}
}
}
}
private static void VerifyFileLockedByOleDB(string fullFileName)
{
string file = Path.GetFileName(fullFileName);
string dir = Path.GetDirectoryName(fullFileName);
string cStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
+ "Data Source=\"" + dir + "\\\";"
+ "Extended Properties=\"text;HDR=Yes;FMT=Delimited\";";
string sqlStr = "SELECT * FROM [" + file + "]";
using (OleDbConnection conn = new OleDbConnection(cStr))
{
OleDbCommand cmd = new OleDbCommand(sqlStr, conn);
conn.Open();
using (OleDbDataReader reader = cmd.ExecuteReader())
{
File.OpenRead(fullFileName); // should throw an exception
while (reader.Read())
{
File.OpenRead(fullFileName); // should throw an exception
StringBuilder b = new StringBuilder();
for (int i = 0; i < reader.FieldCount; i++)
{
b.Append(reader.GetValue(i));
b.Append(",");
}
string line = b.ToString().Substring(0, b.Length - 1);
Console.WriteLine(line);
}
}
}
}
static void Main(string[] args)
{
string filename = Directory.GetCurrentDirectory() + "\\SomeText.CSV";
try
{
VerifyFileLockedByOleDB(filename);
}
catch { } // ignore exception due to locked file
OpenCSVasDBWithLock(filename, delegate(IDataReader row)
{
StringBuilder b = new StringBuilder();
for (int i = 0; i <row.FieldCount; i++)
{
b.Append(row[i].ToString());
b.Append(",");
}
string line = b.ToString().Substring(0, b.Length - 1);
Console.WriteLine(line);
});
}
}
}