Одновременное чтение и запись в файл Excel - PullRequest
0 голосов
/ 17 января 2019

Возможно ли, чтобы только один процесс выполнял WRITE, а многие выполняли операцию READ над файлом Excel? Я использую ExcelPackage (EPPlus) для этого.

Для демонстрации я написал два консольных приложения: одно для итеративной записи, а другое для чтения. Одновременный запуск их приведет к сбою с обеих сторон.

WRITE

// 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++;
    }
}

READ

//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();
}

Ответы [ 2 ]

0 голосов
/ 05 мая 2019

Я немного изменил свой код, заставив программу WRITE заблокировать файл перед записью, и ЧИТАТЬ, чтобы обеспечить устойчивость в случае сбоя:

WRITE: используйте FileStream и заблокируйте его перед попыткой записи. Это предотвратит ошибку WRITE

READ: добавлен механизм повторов, реализующий блок try / catch

Модифицированный код:

WRITE

// 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++;
    }
}

READ

//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 короткие; добавляются строки за раз), и приложение работает хорошо в течение месяца.

0 голосов
/ 17 января 2019

Вы не можете одновременно читать и записывать один и тот же файл, так как он блокируется, когда вы читаете его. Вы можете прочитать весь файл в память, а затем обработать его, а после обработки вы можете записать его обратно.

...