【问题标题】:Using StreamReader / StreamWriter to grab logs causes program to cease responding使用 StreamReader / StreamWriter 抓取日志导致程序停止响应
【发布时间】:2014-06-17 17:07:59
【问题描述】:

我正在尝试使用 StreamReader 和 StreamWriter 从另一个应用程序获取临时输出日志(.txt 格式)。
输出日志始终打开并不断写入。
如果应用程序关闭或崩溃,日志文件最终会被删除——因此需要一个可以从该日志中获取信息并保存的工具。

我的程序目前所做的是:

  • 创建一个新的 .txt 文件,并将该文件的路径存储为 字符串“目标文件”。
  • 找到要读取的 .txt 日志文件,并将该文件的路径存储为 字符串“sourceFile”
  • 然后它将这两个字符串传递给下面的方法。

基本上我是在尝试一次读取 sourceFile 一行。
每次读取一行时,都会将其附加到destinationFile。
这会一直循环,直到 sourceFile 不再存在(即应用程序已关闭或崩溃并删除其日志)。

此外,sourceFile 可能会变得非常大(有时 100Mb+),并且该程序可能一次处理多个日志。
读取整个日志而不是逐行读取很可能会开始消耗相当多的内存。

private void logCopier(string sourceFile, string destinationFile)
{
    while (File.Exists(sourceFile))
    {
        string textLine;
        using (var readerStream = File.Open(sourceFile, 
                                            FileMode.Open, 
                                            FileAccess.Read, 
                                            FileShare.ReadWrite))
        using (var reader = new StreamReader(readerStream))                                      
        {
            while ((textLine = reader.ReadLine()) != null)
            {
                using (FileStream writerStream = new FileStream(destinationFile, 
                                                                FileMode.Append,
                                                                FileAccess.Write))
                using (StreamWriter writer = new StreamWriter(writerStream))
                {
                    writer.WriteLine(textLine);
                }                   
            } 
        }
    }
}

问题是我的 WPF 应用程序在到达此代码时锁定并停止响应。
为了追踪位置,我在代码的 writerStream 行之前放置了一个 MessageBox,以输出阅读器正在接收的内容。
它确实可以很好地读取日志文件,但是将其写入文件似乎存在问题。
一旦它到达代码的 using (FileStream writerStream = new FileStream 部分,它就会停止响应。

以这种方式使用 StreamWriter 是无效的,还是我刚刚在代码中做了一些愚蠢的事情?
我也愿意接受比我在这里尝试做的更好的解决方案。

【问题讨论】:

  • 停止响应?您是否在调试中看到它读取了更多行,或者它完全停止在该行中?如果这发生在主线程上,它将停止其他任何事情,直到它完成读取/复制文件。
  • 我最初删除了代码的整个 StreamWriter 部分,并在那里放置了一个 MessageBox。每次读取新行时都会弹出消息框,因此它会按预期逐行读取。当它停止响应时,我收到消息“问题导致程序停止正常工作。Windows 将关闭该程序并通知您是否有可用的解决方案。”使用 StreamWriter 代码,打开程序创建的文本文件(destinationFile)总是完全空白。似乎没有任何东西被写入它。
  • 好的,但这将“锁定”应用程序的其余部分,直到它完成读取/复制文件。如果您希望应用程序的其他部分在此过程中响应,则需要将应用程序的这一部分放在它自己的单独线程中。
  • 现在有了双重while 构造,sourceFile 不会从头开始重新处理吗?
  • 设法让它工作。感谢 Clemens,我也会在代码中进行更改。第一次使用 StreamReader/Writer,所以还在努力掌握它!

标签: c# wpf streamreader streamwriter


【解决方案1】:

据我所知,您需要将文件从源复制到目标,该文件可能随时被删除。

我建议您使用FileSystemWatcher 来监视源file changed event,然后只需使用File.Copy 将整个文件从源复制到目标。

【讨论】:

    【解决方案2】:

    我刚刚解决了这个问题,这个问题确实很傻!

    在为 StreamWriter 创建文本文件时,我忘记使用 .Dispose();。我有 File.Create(filename); 而不是 File.Create(filename).Dispose(); 这意味着文本文件已经打开,并且 StreamWriter 正在尝试写入已锁定/正在使用的文件。

    UI 仍然锁定(如预期的那样),因为我还没有在 SteenT 提到的新线程上实现它。但是程序不再崩溃,代码正确读取日志并输出到文本文件。

    同样经过一些改进,我的日志读取器/写入器代码现在看起来像这样:

        private void logCopier(string sourceFile, string destinationFile)
        {
            int num = 1;
            string textLine = String.Empty;
            long offset = 0L;
    
            while (num == 1)
            {
                if (File.Exists(sourceFile))
                {
    
                    FileStream stream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                    using (new StreamReader(stream))
                    {
                        stream.Seek(offset, SeekOrigin.Begin);
                        TextReader reader2 = new StreamReader(stream);
                        while ((textLine = reader2.ReadLine()) != null)
                        {
                            Thread.Sleep(1);
                            StreamWriter writer = new StreamWriter(destinationFile, true);
                            writer.WriteLine(textLine);
                            writer.Flush();
                            writer.Close();
                            offset = stream.Position;
                        }
                        continue;
                    }
                }
                else
                {
                    num = 0;
    
                }
            }
        }
    

    只要把这段代码放在这里,以防其他人正在寻找类似的东西。 :)

    【讨论】:

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