【问题标题】:The process cannot access the file because it is being used by another process. (Text File will not close)该进程无法访问该文件,因为它正被另一个进程使用。 (文本文件不会关闭)
【发布时间】:2014-08-28 11:21:33
【问题描述】:

在此代码块检查最后一次重新启动 PC 之后,我正在尝试写入文本文件。下面的代码从文本文件中读取,即最后一次重新启动 PC,并从那里确定是否显示启动画面。但是,在此方法运行后,我需要将当前的“系统正常运行时间”写入文本文件。但我不断收到一个错误,说文本文件正在使用中。这让我发疯了。我已确保所有 StreamWriters 和 StreamReaders 都已关闭。我试过使用语句。我试过 GC.Collect。我觉得我已经尝试了一切。

任何帮助将不胜感激。

    private void checkLastResart()
    {
        StreamReader sr = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + @"\Settings.txt");
        if (sr.ReadLine() == null)
        {
            sr.Close();
            MessageBox.Show("There was an error loading 'System UpTime'. All settings have been restored to default.");
            StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + @"\Settings.txt", false);
            sw.WriteLine("Conversion Complete Checkbox: 0");
            sw.WriteLine("Default Tool: 0");
            sw.WriteLine("TimeSinceResart: 0");
            sw.Flush();
            sw.Close();
        }
        else
        {
            try
            {
                StreamReader sr2 = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + @"\Settings.txt");
                while (!sr2.EndOfStream)
                {
                    string strSetting = sr2.ReadLine();
                    if (strSetting.Contains("TimeSinceResart:"))
                    {
                        double lastTimeRecorded = double.Parse(strSetting.Substring(17));

                        //If the lastTimeRecorded is greater than timeSinceResart (computer has been resarted) OR 2 hours have passed since LVT was last run
                        if (lastTimeRecorded > timeSinceRestart || lastTimeRecorded + 7200 < timeSinceRestart)
                        {
                            runSplashScreen = true;
                        }
                        else
                        {
                            runSplashScreen = false;
                        }
                    }
                }
                sr2.Close();
                sr2.Dispose();
            }
            catch (Exception e) { MessageBox.Show("An error has occured loading 'System UpTime'.\r\n\r\n" + e); }
        }
    }               

以下是运行上述代码后写入文本文件的示例。无论我打开 StreamWriter 还是使用 File.WriteAllLines,都会立即抛出错误。

StreamWriter sw = new StreamWriter(Path.GetDirectoryName(Application.ExecutablePath) + @"\Settings.txt");
            string[] lines = File.ReadAllLines(Path.GetDirectoryName(Application.ExecutablePath) + @"\Settings.txt");
            lines[2] = "TimeSinceResart: " + timeSinceRestart;
            foreach (string s in lines)
                sw.WriteLine(s);

【问题讨论】:

  • 在关闭 else 块中的第一个实例之前,您正在打开第二个版本的 StreamReader
  • 谢谢@entropic 这就是问题所在!我很困惑,因为我在 if 语句打开后立即关闭了 StreamReader。为什么我需要再次关闭它?此外,如果在 if 语句关闭之前 sr 实际上没有关闭,为什么它允许我打开 StreamWriter 的实例来访问该文件?
  • 什么意思?如果您在 else 块中,则 if 块中的任何内容都不会执行 - 所以您永远不会真正关闭第一个 StreamReader....
  • @entropic 哦,没错!我知道了。谢谢你指出这一切。我希望我能更好地观察那些愚蠢的错误。希望通过练习我会变得更好。

标签: c# .net streamreader streamwriter


【解决方案1】:

你的写代码应该这样改

string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");

// First read the two lines in memory
string[] lines = File.ReadAllLines(file);

// then use the StreamWriter that locks the file
using(StreamWriter sw = new StreamWriter(file))
{
     lines[2] = "TimeSinceResart: " + timeSinceRestart;
     foreach (string s in lines)
         sw.WriteLine(s);
}

这样,StreamWriter 上的锁不会阻塞 FileReadAllLines 的读取。
说了这么多,请注意几点。不要使用字符串连接创建路径字符串,使用 Path 类的静态方法。但最重要的是,当您创建像流这样的一次性对象时,请务必使用using statement 正确关闭文件

完成回答您的评论。代码的第一部分也使用 using 语句

private void checkLastResart()
{
    string file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"Settings.txt");
    using(StreamReader sr = new StreamReader(file))
    {
        if (sr.ReadLine() == null)
        {
            sr.Close();
            MessageBox.Show(...)
            using(StreamWriter sw = new StreamWriter(file, false))
            {
                sw.WriteLine("Conversion Complete Checkbox: 0");
                sw.WriteLine("Default Tool: 0");
                sw.WriteLine("TimeSinceResart: 0");
                sw.Flush();
            }
        }
        else
        {
            ....
        }
    } // exit using block closes and disposes the stream
}

【讨论】:

  • 这不是我实际问题的正确答案;但是,它是等待发生的错误的正确解决方案。 (它确实发生在我修复了它之前执行的代码块中的初始错误之后)。
  • 这不是我实际问题的正确答案;但是,它是等待发生的错误的正确解决方案。我遇到的错误的实际解决方案是因为在“if 语句”完成后我没有关闭 StreamReader sr。我很困惑,因为我确实在 if 语句打开后立即关闭了该 sr,但它也需要在 if 语句完成后关闭。在我修复了在它之前执行的代码块中的初始错误之后,您正在谈论的错误发生在我身上。非常感谢:)
  • 我明白了,使用 using statement 的另一个原因有助于避免这种错综复杂的情况
  • 我对 c# 还很陌生,从我收集到的内容是 using 语句基本上是在设定范围内使用对象/方法/等的一种方式? using 语句会自动关闭/处理所有内容,而无需我手动指定吗?
【解决方案2】:

在您创建sr2 的位置,sr 仍然打开 settings.txt。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-10
    相关资源
    最近更新 更多