如何使用Jet OLEDB打开CSV或XLS并获得表锁?

我试图找出当我通过Jet OLEDB将其作为数据库读取时如何读取/写入锁定CSV或XLS文件。

以下代码将CSV作为DB打开并将其加载到DataTable对象中:

private 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; } } 

我想确定的是,当我打开CSV或XLS文件时,我在表(也就是文件)上有一个读/写锁定,以便任何其他应用程序出现并尝试读取/写入此文件必须等待。

这会自动发生吗? 如果没有,我需要做些什么来确保确实发生这种情况?

顺便说一句,我在C#/。NET 2.0工作,如果这有任何区别……

更新:所以,我现在澄清我的要求:

  • XLS文件(因为我需要SELECT和UPDATEfunction)[CSV只能SELECT和INSERT]
  • 数据库处于打开状态时锁定XLS文件。 (不能让多个线程和/或进程踩到彼此的变化……)
  • 读入DataTable对象(为了便于工作)

OLEDB的Jet驱动程序锁定平面文件,同时打开OleDbDataReader。 要validation这一点,请查看下面的代码示例中的VerifyFileLockedByOleDB方法。 请注意,打开OleDbConnection是不够的 – 你必须有一个打开的Reader。

也就是说,上面发布的代码不会保持打开连接,因为它使用OleDbDataAdapter.Fill()快速连接到数据源,取出所有数据,然后断开连接。 读者永远不会被打开。 该文件仅在Fill()运行的(短)时间内被锁定。

此外,即使您自己打开阅读器并将其传递给DataTable.Load() ,该方法也会在您完成后关闭DataReader,这意味着文件将被解锁。

因此,如果您真的想要保持文件锁定并仍然使用DataTable,则需要从IDataReader手动填充数据表(模式和行!),而不是依赖于DataAdapter.Fill()或DataTable.Load() 。

无论如何,这是一个代码示例,显示:

  • 你的原始代码
  • 一个不起作用的示例,因为DataTable.Load()将关闭DataReader并解锁文件
  • 通过使用DataReader在行级操作而不是使用DataTable,在您处理数据时保持文件锁定的替代方法

更新:看起来保持DataReader打开将阻止相同的进程打开文件,但另一个进程(例如Excel)可以打开(并写入!)文件。 去搞清楚。 无论如何,在这一点上,我建议,如果你真的想保持文件锁定,可以考虑使用除OLEDB之外的其他东西,你可以更精细地控制文件打开和关闭的方式(adn when!)。 我建议使用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 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  

更新:以下似乎没有锁定我的数据库,因为我希望…

经过更多的挖掘,我找到了这个页面:

ADO提供程序属性和设置

它说:

Jet OLEDB:数据库锁定模式

Long值(读/写),指定锁定数据库以读取或修改记录时使用的模式。

Jet OLEDB:数据库锁定模式属性可以设置为以下任何值:

页面级锁定0

行级锁定1

注意数据库一次只能以一种模式打开。 第一个打开数据库的用户确定在数据库打开时要使用的锁定模式。

所以我假设我的代码将更改为:

  string cStr = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=\"" + dir + "\\\";" + "Extended Properties=\"text;HDR=Yes;FMT=Delimited\";" + "Jet OLEDB:Database Locking Mode=0"; 

哪个应该给我页面级锁定。 如果我想要行级锁定,我会将值切换为1。

不幸的是,在将CSV文件作为数据库打开时,这实际上似乎不会执行任何表/行/页锁定。

好的,所以你写的新function有点工作,但我仍然最终得到一个“竞争条件”,然后引发exception。 所以在这段代码中:

  using (OleDbConnection conn = new OleDbConnection(cStr)) { OleDbCommand cmd = new OleDbCommand(sqlStr, conn); conn.Open(); using (OleDbDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { reader.GetString(0); // breakpoint here } } } 

我在一行中添加了一个断点,注释“breakpoint here”,然后运行程序。 然后我将CSV文件放在文件资源管理器中,并尝试用Excel打开它。 它会导致Excel等待文件解锁,这很好。

但这是不好的部分。 当我清除断点然后告诉它继续调试时,Excel会悄悄进入,抓取文件锁定并在我运行的代码中导致exception。

(例外情况是:Microsoft Jet数据库引擎无法打开文件”。它已由其他用户独占打开,或者您需要获得查看其数据的权限。)

我想我总是可以将该代码包装在try-catch块中,但是当exception发生时,我不知道它是一个合法的exception还是由于这种奇怪的情况引起的exception。

Reader完成阅读后似乎发生exception。 (在读取最后一行之后,仍然在“using(OleDbDataReader reader = cmd.ExecuteReader())”循环中。