【问题标题】:TextWriter.WriteLine IO Exception - The specified network name is no longer availableTextWriter.WriteLine IO 异常 - 指定的网络名称不再可用
【发布时间】:2012-09-17 01:20:26
【问题描述】:

我在从控制台应用程序中的大型制表符分隔文本文件读取后尝试写入文本文件。问题是,如果我在服务器上同时运行此 exe 的多个实例,它会在 TextWriter.WriteLine 处给我运行时错误,然后由于未处理的异常而导致应用程序崩溃。所有实例都会发生这种情况。我无法理解这种行为的原因。是因为我没有使用 StringBuilder 会动态使用内存吗?

我的代码如下:

 StreamReader sr = new StreamReader(@FilePath, System.Text.Encoding.Default);
 string mainLine = sr.ReadLine();
 string[] fileHeaders = mainLine.Split(new string[] { "\t" }, StringSplitOptions.None);
 string newLine = "";

 System.IO.StreamWriter outFileSw = new System.IO.StreamWriter(@outFile);

 while (!sr.EndOfStream)
 {
    mainLine = sr.ReadLine();
    string[] originalLine = mainLine.Split(new string[] { "\t" }, StringSplitOptions.None);

   newLine = "";
   for (int i = 0; i < fileHeaders.Length; i++)
   {
      if(fileHeaders[i].Trim() != "")
       newLine = newLine + fileHeaders[i].Trim() + "=" + originalLine[i].Trim() + "&";
   }

outFileSw.WriteLine(newLine.Remove(newLine.Length - 1));
FileInfo fileInfo = new FileInfo(@outFile);

  if (fileInfo.Length > (1.3 * 1024.0 * 1024.0 * 1024.0)) // greater than 1.3 GB  
  {
          outFileSw.Close();
          outFileNumber = outFileNumber + 1;
          outFileSw = new System.IO.StreamWriter(@outFile + outFileNumber.ToString() + ".txt");
  }

}
outFileSw.Dispose();
sr.Close();
sr.Dispose();

错误详情是:

Exception Message: The specified network name is no longer available.

Stack Trace:    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
 at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
 at System.IO.FileStream.Write(Byte[] array, Int32 offset, Int32 count)
 at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
 at System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count)
 at System.IO.TextWriter.WriteLine(String value)
 at ExampleExe.ExampleProcess.FnFiles()


 Unhandled Exception: System.IO.IOException: The specified network name is no longer available.

 at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
 at System.IO.FileStream.WriteCore(Byte[] buffer, Int32 offset, Int32 count)
 at System.IO.FileStream.FlushWrite(Boolean calledFromFinalizer)
 at System.IO.FileStream.Dispose(Boolean disposing)
 at System.IO.FileStream.Finalize()

谢谢, 卡努

【问题讨论】:

  • 你曾经关闭过这些文件吗? using(){} 在这些情况下非常有用。
  • @nrodic:是的。我在处理完我正在阅读的完整文件后关闭并处理。此外,当应用程序尝试写入文件时会发生错误。
  • @nordic:我编辑了问题文本以显示我如何关闭和处置...
  • 你写的是网络路径吗?理想情况下,您希望缓冲而不是写入每一行,这会减少原始 IO 的数量。您可以缓冲例如在将内容转储到文件之前,需要 10MB 到 stringbuider 或字节缓冲区。
  • 尝试进行网络跟踪和 filemon 跟踪。

标签: c# console-application windows-server-2003 ioexception streamwriter


【解决方案1】:

这是一个带有 StringBuilder 缓冲区的 FileWriter。它使用单独的线程进行写入,而主线程不断累积数据。一次写入 10MB 缓冲区。缓冲数据保存在 Queue 对象中; writer 线程从此队列中删除项目,并使用 File.AppendAllText 方法将其全部写入。

private Queue<StringBuilder> writeQueue;
private bool isComplete;

public void FileWriter()
{
    this.isComplete = false;
    this.writeQueue = new Queue<StringBuilder>();

    var writer = new Action<string>(this.StartWriting);
    var writerAsync = writer.BeginInvoke(@"outputfile.txt", null, null);

    using (StreamReader sr = new StreamReader(@"inputfile.txt"))
    {
        var fileHeaders = sr.ReadLine()
            .Split('\t')
            .Where(i => !string.IsNullOrEmpty(i))
            .Select(j => j.Trim())
            .ToList();

        var buffer = new StringBuilder();
        while (!sr.EndOfStream)
        {
            var originalLine = sr.ReadLine()
                .Split('\t')
                .Where(i => !string.IsNullOrEmpty(i))
                .Select(j => j.Trim())
                .ToList();

            var line = new StringBuilder();
            //Must have same number of items
            if (originalLine.Count == fileHeaders.Count)
            {
                for (int i = 0; i < fileHeaders.Count(); i++)
                {
                    line.AppendFormat("{0}={1}&", fileHeaders[i], originalLine[i]);
                }
                line.AppendLine();
            }

            buffer.AppendLine(line.ToString());
            if (buffer.Length > 1024 * 1024 * 10)//approx 10MB 
            {
                lock (this.writeQueue)
                {
                    this.writeQueue.Enqueue(buffer);
                }
                buffer = new StringBuilder();
            }
        }
        //Queue any final remaining data
        if (buffer.Length>0) lock (this.writeQueue)
        {
            this.writeQueue.Enqueue(buffer);
        }
    }
    this.isComplete = true;
    writer.EndInvoke(writerAsync);
}

private void StartWriting(string outFilePath)
{
    while (!this.isComplete || this.writeQueue.Count > 0)
    {
        StringBuilder queuedItem;
        if (this.writeQueue.Count > 0)
        {
            lock (this.writeQueue)
            {
                queuedItem = this.writeQueue.Dequeue();
            }
            File.AppendAllText(outFilePath, queuedItem.ToString());
        }
        System.Threading.Thread.Sleep(5000); //Sleep 5sec
    }
}

【讨论】:

  • 还有一个问题......即使我使用缓冲区,我同时运行的线程数仍然会受到限制,具体取决于服务器?
  • 线程数会受到 CPU 时间和资源的限制。您将不得不用不同的数字测试什么是最佳的,以查看什么是最佳的。尝试使用 2 并向上移动,直到您看不到任何性能提升。但最终您将受到网络流量的瓶颈,无法完成远程文件写入。另外,如果您要使用它,请接受它作为答案并投票。
猜你喜欢
  • 1970-01-01
  • 2016-01-13
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-25
  • 2018-11-24
  • 1970-01-01
相关资源
最近更新 更多