并发读取和写入 Excel 文件



是否可以只有一个进程执行写入,而多个进程对 excel 文件执行读取操作?我正在使用ExcelPackage(EPPlus)来解决这个问题。

为了演示,我编写了两个控制台应用程序,一个用于迭代编写,另一个用于读取。同时运行它们将导致任何一端失败。

// simply write to a column
var fileLocation = "D:\Book.xlsx";
FileInfo fi = new FileInfo(fileLocation);
int i = 1;
while (1 == 1)  //ALERT: an infinite loop!
{
    using (ExcelPackage excelPackage = new ExcelPackage(fi))
    {
        ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets["Sheet1"];
        var row = worksheet.Row(2);
        worksheet.Cells[$"A{i}"].Value = "Test " + i.ToString();
        excelPackage.Save();
        i++;
    }
}

//simply populate a list reading excel
var fileLocation = "D:\Book.xlsx";
FileInfo fi = new FileInfo(fileLocation);
List<string> list = new List<string>();
ExcelWorksheet worksheet = null;
int i = 1;
while (1 == 1)  //ALERT: an infinite loop!
{
    using (ExcelPackage excelPackage = new ExcelPackage(fi))
    {
        worksheet = excelPackage.Workbook.Worksheets["Sheet1"];
        if (worksheet.Cells[i, 1].Value != null)
        {
            list.Add(worksheet.Cells[i, 1].Value.ToString());
        }
    }
    list.Clear();
}

我稍微改变了我的代码,让 WRITE 程序在写入之前锁定文件,并在发生故障时 READ 具有弹性:

写入

:使用文件流并在尝试写入之前将其锁定。这将防止写入失败

读取:添加了实现 try/catch 块的重试机制

修改后的代码:

// simply write to a column
var fileLocation = "D:\Book.xlsx";
FileInfo fi = new FileInfo(fileLocation);
int i = 1;
while (1 == 1)  //ALERT: an infinite loop!
{
    using (ExcelPackage excelPackage = new ExcelPackage(fi))
    {
        ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets["Sheet1"];
        worksheet.Cells[$"A{i}"].Value = "Test " + i.ToString();
        using (var fs = new FileStream(fileLocation, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
        {
            fs.Lock(0, fs.Length);
            excelPackage.SaveAs(fs);
            try
            {
                fs.Unlock(0, fs.Length); // this raises an exception if fs unlocked already by itself
            }
            catch (IOException ex) when (ex.Message.ToLower().StartsWith("the segment is already unlocked.",
                StringComparison.InvariantCultureIgnoreCase))
            {
                // NOP; just ignore if already unlocked
            }
        }
        i++;
    }
}

//simply populate a list reading excel
var fileLocation = "D:\Book.xlsx";
FileInfo fi = new FileInfo(fileLocation);
List<string> list = new List<string>();
ExcelWorksheet worksheet = null;
int i = 1;
while (1 == 1)  //ALERT: an infinite loop!
{
    try
    {
        using (ExcelPackage excelPackage = new ExcelPackage(fi))
        {
            worksheet = excelPackage.Workbook.Worksheets["Sheet1"];
            if (worksheet.Cells[i, 1].Value != null)
            {
                list.Add(worksheet.Cells[i, 1].Value.ToString());
            }
            Console.WriteLine(worksheet.Dimension.Rows.ToString()); // just prove that it read
        }
    }
    catch (Exception ex) when (
        ex is IOException &&
        ex.Message.StartsWith("The process cannot access the file because another process has locked a portion of the file.", StringComparison.InvariantCultureIgnoreCase))
    {
        Console.WriteLine($"Attempt: {i}");
    }
    list.Clear();
}

在实际应用程序的代码中,我将 READ 的 WHILE 限制设置为 3,以便在第一次读取尝试失败时重试两次。事实证明,就我而言,这已经绰绰有余了(因为 WRITE 很短;一次附加一行),并且该应用程序运行了一个多月。

您不能同时读取和写入同一文件,因为它在读取时会被锁定。您可以将整个文件读入内存,然后可以对其进行处理,处理后可以将其写回。

相关内容

  • 没有找到相关文章

最新更新