【问题标题】:Avoid "file in use by another process" IO exception避免“文件正在被另一个进程使用”IO异常
【发布时间】:2018-01-30 16:52:18
【问题描述】:

我在下面包含的代码已成功写入 CSV 文件。但是,如果我正在写入的 CSV 文件恰好在 Excel 中打开,我会收到一个 System.IO.Exception,表示“该文件正在被另一个进程使用。”

如何更改我的代码以使程序继续运行并等到 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();
        }
    }

【问题讨论】:

  • 如果文件在 Excel 中打开,您将无法覆盖该文件,因为 Excel 会锁定它。如果遇到 IO 错误,您始终可以使用唯一名称再次写入文件。
  • @AlexK。感谢您的快速回答,我该怎么做?
  • 尝试/捕捉该异常?

标签: c# exception io wait ioexception


【解决方案1】:

您可以编写一个 Methode 尝试使用 FileStream 打开文件并返回一个布尔标志

一个可能的解决方案是

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

【讨论】:

    【解决方案2】:

    你可以看看这个问题:

    Checking if an Excel Workbook is open

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

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

    int someLargeNumberOfIterations = 100000000;
    
    while(FileIsLocked(filepath) && elapsedMs < timeoutMs) {
       Thread.SpinWait(someLargeNumberOfIterations);
    
       // Set elapsed
    }
    
    // Write the file
    

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

    【讨论】:

      猜你喜欢
      • 2013-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-06
      • 1970-01-01
      • 2013-03-10
      • 2018-10-21
      • 1970-01-01
      相关资源
      最近更新 更多