避免 "file in use by another process" IO 异常

Avoid "file in use by another process" IO exception

我在下面包含的代码成功写入了 CSV 文件。但是,如果我正在写入的 CSV 文件恰好在 Excel 中打开,我会得到一个 System.IO.Exception,表明 "the file is being used by another process."

如何更改我的代码以便程序继续 运行 并等待 CSV 在 Excel 中不再打开?

private void timer1_Tick(object sender, EventArgs e)
    {
        int actmonth, actyear, actsecond;
        System.DateTime fecha = System.DateTime.Now;
        actmonth = fecha.Month;
        actyear = fecha.Year;
        if (actmonth <= 9)
        {
            valorfechaact = System.Convert.ToString(actyear) + "00" + System.Convert.ToString(actmonth);
        }
        else
        {
            valorfechaact = System.Convert.ToString(actyear) + "0" + System.Convert.ToString(actmonth);
        }

        actsecond = fecha.Second;

        string label;
        label = label1.Text;
        string at = "@";
        string filename = valorfechaact + ".csv";

        string ruta3 = System.IO.Path.Combine(at, label, filename); 
        if (Directory.Exists(label1.Text))
        {
            StreamWriter wr = new StreamWriter(ruta3, true);
            wr.WriteLine("1asd" + actsecond);
            wr.Close();
            wr.Dispose();
        }
        else
        {
            System.Console.WriteLine("no se puede escribir en el archivo");
            timer1.Stop();
        }
    }

你可以看看这个问题:

Checking if an Excel Workbook is open

所讨论的方法之一是简单地尝试访问该文件。如果抛出异常,您可以等待并重试。

如果你真的想等到工作簿可写,你可以这样做,例如通过使用 while 循环(可能您想要添加超时,或者如果相关提醒用户 he/she 需要关闭 Excel 中的文件)。 在代码中它可能是这样的:

int someLargeNumberOfIterations = 100000000;

while(FileIsLocked(filepath) && elapsedMs < timeoutMs) {
   Thread.SpinWait(someLargeNumberOfIterations);

   // Set elapsed
}

// Write the file

其中 FileIsLocked 是您根据上述 post 编写的函数,而 timeoutMs 是一些适当的超时。

您可以编写一个尝试使用 FileStream 和 return 布尔标志

打开文件的 Methode

一个可能的解决方案是

public static class FileInfoExtension
{
    public static bool IsLocked(this FileInfo file)
    {
        FileStream stream = null;
        try
        {
            stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
        }
        catch (IOException)
        {
            return true;
        }
        finally
        {
            stream?.Close();
        }
        return false;
    }
}

那你就可以用了

    var fileInfo = new FileInfo(ruta3);
    if (!fileInfo.IsLocked())
    {
       // do code
    }

一个非常简单(而且不好)的等待解决方案是

    while (file.IsLocked())
    {
       Thread.Sleep(100);
    }

一般是您的代码不清楚且难以阅读。

你有很多多余的代码,很少有变量命名错误。 也许这个指南可以帮助你 https://github.com/dennisdoomen/CSharpGuidelines

也许更清晰一点的解决方案是

    private void timer1_Tick(object sender, EventArgs e)
    {
        var directory = label1.Text;
        if (!Directory.Exists(directory))
        {
            Console.WriteLine("no se puede escribir en el archivo");
            timer1.Stop();
            return;
        }
        var now = DateTime.Now;
        _valorfechaact = now.Month <= 9 ? $"{now.Year}00{now.Month}" : $"{now.Year}0{now.Month}";
        var fullname = Path.Combine("@", directory, $"{_valorfechaact}.csv");
        var fileInfo = new FileInfo(fullname);
        if (fileInfo.IsLocked())
        {
            Console.WriteLine($"The File {fullname} is locked!");
            return;
        }
        using (var wr = new StreamWriter(fullname, true))
        {
            wr.WriteLine("1asd" + now.Second);
        }
    }