【问题标题】:Read Excel file with OleDB c#, when it is used by other process使用 OleDB c# 读取 Excel 文件,当它被其他进程使用时
【发布时间】:2013-09-14 06:18:24
【问题描述】:

我正在尝试每 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 个月开始尝试这个。请帮帮我吧

【问题讨论】:

  • 嗯,你需要得到什么?您不能简单地捕获异常并在(比方说)500 毫秒后重试吗?如果这不可行,您可以简单地使用 File.Copy 制作副本,然后打开副本。遗憾的是,您不能要求 OleDB 驱动程序在实例之间共享文件。
  • @Adriano,首先感谢您给我们时间,我正在做同样的重试,但正在寻找更好的方法,复制文件的问题是文件数据没有保存在硬盘上。这个excel文件是在电脑上打开的。您能否分享一下代码/方式,我可以每 2 秒保存/复制该文件,然后读取该文件
  • 我肯定会按照@Adriano 在他的回复中的建议使用 FileSystemWatcher

标签: c# excel


【解决方案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 文件,有许多 3rd 免费库不使用独占锁打开文件,例如 this one
  • 不要直接从文件中读取数据,如果 Microsoft Excel 实例一直在运行,您可以使用 COM 互操作来获取通知。检查this general article 了解 COM 加载项和this,了解如何将具有 Office Interop 的 C# 应用程序附加到现有 Microsoft Excel 实例。

【讨论】:

  • 感谢 Adriano,FileSystemWatcher 可能是最佳选择,但这里的情况完全不同,此 excel 文件正在由某些 DDE (RTD) 更新但它不保存 excel 文件它只是更新我们可以手动查看/读取的 excel 单元格中的值
  • 亲爱的所有主要障碍之一是每当在此 excel 中更新数据时,它不会保存在硬盘上(如果我们尝试从文件流中读取数据,那么它会提供旧数据,可以2 小时或更长时间),我尝试了 10 多种方法,发现只有 OleDB 能够从 Excel 文件中读取未保存的数据
  • 我已经尝试过这个 ReadOnly = True,但结果是一样的 :(
  • @NidhiSharma 很有趣!我进行了快速搜索,并且……最常见的建议是不要为此使用 OleDB。如果它对你有用,可以试试exceldatareader.codeplex.com
  • @NidhiSharma read this 了解 COM 加载项的一般介绍。试试this article,即使有点旧,它也可以工作,看看如何附加到正在运行的 Excel 实例。
【解决方案2】:

不确定,您为什么要按照您的方式阅读 excel。

您可以尝试LinqToExcel 进行excel 阅读,它是一个不错的阅读excel 文件的小库,如果您需要创建excel 然后尝试EPPLUS 库。我个人发现这些库在使用 Excel 时非常有效

【讨论】:

    【解决方案3】:

    我有类似的问题。以下修复对我有用

    1) 不要保持与工作表的连接。而是打开连接读取数据并立即关闭连接。

    2) 如果您在非托管应用程序中使用托管代码,请考虑使用托管类型的对象而不是指针(使用 gcnew)并使用Stack Semantics 确保在对象超出范围时清理内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-18
      • 2010-11-17
      • 2013-08-11
      相关资源
      最近更新 更多