当其他进程使用 OleDB c# 读取 Excel 文件时
本文关键字:读取 Excel 文件 OleDB 其他 进程 | 更新日期: 2023-09-27 18:31:12
我正在尝试每 2 秒读取一个 excel 文件,此文件正在被其他 RTD 应用程序更新。
我能够通过 Oledb 连接读取此文件,但是当我尝试每 2 秒读取一次它时出现问题。在 10 次尝试中,它只能读取 4-5 次,在其他尝试中,它会引发异常。
连接字符串
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:'nids'shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1"
法典
//opening connection to excel file
using (OleDbConnection connection = new OleDbConnection(constr))//constr = connection string
{
try
{
connection.Open();
isconopen = true;
}
catch
{
dispatcherTimer2.Start();
connection.Close();
isconopen = false;
}
// If connection is ok , then query sheet
if (isconopen == true)
{
strcon = "SELECT * FROM [" + dsheet + "]";
using (OleDbDataAdapter adapter = new OleDbDataAdapter(strcon, connection))
{
try
{
adapter.Fill(result);
isread = true;
adapter.Dispose();
connection.Close();
}
catch
{
isread = false;
dispatcherTimer2.Start();
adapter.Dispose();
connection.Close();
}
}
}
//if able to retrieve data then call some other function
if (isread == true)
{
converToCSV(0);// for further processing
}
请帮助我,我正在从过去 1 个月开始尝试这个。拜托请请帮帮我
遗憾的是,默认情况下,OleDB 驱动程序将专门打开文件,然后当其他人使用它时,即使只是为了阅读,您也无法打开它。
两个注意事项:
- 其他应用程序可能会在几毫秒内完成其对文件的工作,因此最好重试
- 驱动程序将始终打开锁定的文件进行写入(因此您无法通过 OleDB 打开它两次),但它是共享以供读取的(因此您可以复制它)。
也就是说,我建议您在短暂暂停后首先尝试打开它,如果它仍在使用中(并且您不能等待更多),那么您可以复制并打开它。
让我假设您的代码位于HandlExcelFile()
函数中:
void HandleExcelFile(string path)
{
try
{
// Function will perform actual work
HandleExcelFileCore(path);
}
catch (Exception) // Be more specific
{
Thread.Sleep(100); // Arbitrary
try
{
HandleExcelFileCore(path);
}
catch (Exception)
{
string tempPath = Path.GetTempFileName();
File.Copy(path, tempPath);
try
{
HandleExcelFileCore(tempPath);
}
finally
{
File.Delete(tempPath);
}
}
}
}
代码有点难看,所以只需将其视为编写自己的函数的起点。
考虑:
- 重试并不是一件坏事,它是解决此类问题的常用方法。例如,这就是Windows shell所做的(对于网络来说更正常)。
- 如果应用程序没有关闭文件,那么您可以复制(和读取)旧数据。如果您总是需要最新的数据,那么您只有一个选择:等待。如果你可以假设未保存的数据属于上一个时间范围(T - 1,就像在数字电子中,当信号边沿在时钟边沿时),那么就去做吧,然后快乐地生活。
未经测试的解决方案:
我没有尝试这个,所以你必须自己做。实际上(我最初错了)您可以打开只读连接(通过扩展属性)。如果这仅适用于连接或同时适用于文件句柄和连接,则不会记录。无论如何,让我们尝试将连接字符串更改为:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:'nids'shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1;ReadOnly=true"
刚刚在Extended Properties
末尾添加了一个ReadOnly=true
.
其他解决方案:
- 我想到的唯一替代解决方案是...手动读取Excel文件(因此您可以打开它进行阅读)。也就是说,即使在这种情况下,其他应用程序也可能没有写入新数据(因此您将读取旧数据)。
- 根本不要使用计时器。将设计更改为使用
FileSystemWatcher
,只有在收到文件已更改的通知时,您才会读取该文件。 - 如果适用...只是不要使用共享文件作为IPC机制!好吧,您可能无法更改第二个应用程序,因此可能不是这种情况。
- 不要使用 OleDB 读取Microsoft Excel 文件,有许多第 3 部分免费库不会使用独占锁打开文件,例如这个。
- 不要直接从文件中读取数据,如果 Excel 实例始终运行Microsoft则可以使用 COM 互操作来获取通知。查看这篇有关 COM 加载项的一般文章,了解如何将 C# 应用程序与 Office 互操作附加到现有的 Microsoft Excel 实例。
不确定,为什么你想以你正在做的方式阅读 excel。
您可以尝试LinqToExcel进行Excel阅读,这是一个不错的小库,用于读取Excel文件,如果您需要创建excel,请尝试EPPLUS库。我个人发现这些库在使用 Excel 时非常有效
我也有类似的问题。以下修复对我有用
1) 不要将连接固定在工作表上。而是打开连接读取数据并立即关闭连接。
2) 如果您在非托管应用程序中使用托管代码,请考虑使用托管类型的对象而不是指针(使用 gcnew),并使用堆栈语义来确保在对象超出范围时清理内存。