如何最高效的读取Excel文件?

rock29 2016-06-12 11:36:12
需要读取一excel文件内容进行处理,此文件共约700条数据,(每条数据约12项)。每隔三分钟会有一第三方程序向此文件写入一条数据。此第三方程序不可进行二次开发,且具有最高权限,就是说此第三方程序写入数据时,其它程序不得对excel文件进行占用。请问此问题如何解决。
我的思路是尽量快速读取excel文件数据然后关闭excel文件。把读取的数据生成dataset在计算机内存中处理而不在打开excel文件时一边读数一边处理。
那么哪位高人可以给我一个读取快速excel文件数据并生成dataset的例子?愿给500分!
注意,使用读取数据库的方法读取excel文件并生成dataset方法不可取,因为一:使用此方法必须建立数据库连接,这个过程需要耗费时间,且如果网络有问题的话时间会更长。二直接读取excel文件,按照标准的读取excel文件的range方法不可取,时间太长!
...全文
254 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
rock29 2016-06-13
  • 打赏
  • 举报
回复
二楼: 1 第三方程序每隔三分钟就操作一下excel,这意味着我每隔三分钟就要拷贝一下文件,首先二十四小时对文件要拷贝许多次,而且并不只有这一个excel,实际我一次要操作大约二十个excel文件。此方法还对硬盘频繁操作,损伤寿命(机器除非断电,否则终年不停机) 2 我说了,打开文件方法不可取,因为一是用此方法读取数据太慢(一个不明显,二十个*700*12是龟速),且我记得在visual studio中需要调用excel实例才能打开此文件,这个打开文件的动作似乎是独占的,如何读写共享呢?如果真可以共享,那么我读取数据时,第三方程序此时写入一条数据,然后关闭文件,由于数据有变化,那么excel文件关闭时必然弹出保存对话框,这就需要人工确认。而实际这是无人操作,无法进行保存确认的。 三楼:我的程序不能对excel文件进行任何改变内容的操作。实际上这个文件是由那个第三方程序自动生成,自动写入数据。我的程序只能趁它不操作此文件时读取一下数据,其它什么都不能干! 我主要是想解决当我对此文件独占使用时,恰好第三方程序也对其使用而引发的冲突问题,而此时要求第三方程序必须具有最高权限,不能影响它对excel文件的使用,且无法更改第三方程序代码。 我目前的思路只能是尽快的对此文件数据读出来,然后关闭文件供第三方程序使用。当然这仍然无法保证百分百可以解决冲突问题,但可以使冲突可能性尽量降低到最小。
龍过鸡年 2016-06-13
  • 打赏
  • 举报
回复
上面的代码有个问题,path 复用,前面的 string 要去掉。
龍过鸡年 2016-06-13
  • 打赏
  • 举报
回复
首先参考 Get instance of Excel application with C# by Handle http://stackoverflow.com/questions/1118735/get-instance-of-excel-application-with-c-sharp-by-handle


using Excel = Microsoft.Office.Interop.Excel;

public Excel.Application StartExcel()
{
    Excel.Application instance = null;
    try
    {
       instance = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
       instance = new Excel.ApplicationClass();
    }
    return instance;
}
可以直接从系统中获取已存在的 excel 实例,应该可以解决文件被独占访问的问题。 第二步,判断文件是否已打开

var xls = StartExcel();
foreach (Excel.Workbook wb in xls.Workbooks)
{
    if(wb.Path == path) // 文件是否打开判断
}
第三步,利用二维数组映射数据,快速读取

object[,] arr = (object[,])sh.UsedRange.Value;
测试: 文件包含一张表 7 个字段,2542 行数据 关闭状态用时 < 300 ms 打开状态用时 < 50 ms


using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;

// 获取系统中已存在的 Excel Application 实例
public Excel.Application GetInstance()
{
    Excel.Application instance = null;
    try
    {
        instance = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
    }
    catch (System.Runtime.InteropServices.COMException ex)
    {
        Console.WriteLine(ex.Message);
        instance = new Excel.Application();
    }
    return instance;
}

private void meOnClick(object sender, RoutedEventArgs e)
{
    Stopwatch sw = new Stopwatch(); // 启动一个计时器
    sw.Start();

    Excel.Application xls = GetInstance(); // 获取 Excel 实例
    Excel.Workbook wb = null;
    Excel.Worksheet sh;

    bool openByMe = false; // 用于标识是否是自己的程序打开的文件

    // 程序目录中放了一个测试用的 xlsx
    // 表中有 7 个字段 2542 行数据
    string path = System.IO.Path.GetFullPath("test.xlsx");

    foreach (Excel.Workbook item in xls.Workbooks)
    {
        // 通过路径判断文件是否已被打开
        if (item.FullName == path)
        {
            wb = item;
            break;
        }
    }

    if (wb == null) // 判断文件是否已打开
    {
        try
        {
            wb = xls.Workbooks.Open(path, ReadOnly: true); // 已只读方式打开文件
            openByMe = true; // 是自己的程序打开的
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    if (wb == null)
        return;

    sh = (Excel.Worksheet)wb.Sheets["systems"]; // 获取目标 Worksheet

    object[,] arr = (object[,])sh.UsedRange.Value; // 以最快的方式获取数据

    if (openByMe) // 判断标识
    {
        wb.Close(SaveChanges: false); // 关闭文件
        xls.Quit(); // 退出 Excel

        sh = null;
        wb = null;
        xls = null;
    }

    Console.WriteLine("{0}", sw.Elapsed.TotalMilliseconds);

    if (arr == null) // 判断是否获取了数据
        return;

    var sb = new StringBuilder();

    // 将数组数据植入 StringBuilder
    for (int i = arr.GetLowerBound(0); i <= arr.GetUpperBound(0); i++)
    {
        for (int j = arr.GetLowerBound(1); j <= arr.GetUpperBound(1); j++)
        {
            if (j == arr.GetLowerBound(1))
            {
                sb.AppendFormat("{0}", arr[i, j]); // 首个字段直接写值
            }
            else
            {
                sb.AppendFormat("\t{0}", arr[i, j]); // 非首字段写\t+值
            }
        }
        sb.AppendLine(); // 写入回车
    }

    // 获取一个 cache.csv 文件路径,该文件位于当前应用程序目录
    string path = System.IO.Path.GetFullPath("cache.csv");
    System.IO.File.WriteAllText(path, sb.ToString(), Encoding.Default); // 写入数据

    sw.Stop();
    Console.WriteLine("{0}", sw.Elapsed.TotalMilliseconds);
}
threenewbee 2016-06-12
  • 打赏
  • 举报
回复
第三方程序是怎么写 excel的,你每次读取完了,就把excel初始化下,使得它清空,不就可以了。
Poopaye 2016-06-12
  • 打赏
  • 举报
回复
那你还不如读之前把excel复制一份,想读多久都没关系 或者开文件时候开启读写共享

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧