1

在从控制台应用程序中的大型制表符分隔的文本文件中读取后,我正在尝试编写文本文件。问题是,如果我在服务器上同时运行此 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()

谢谢,卡努

4

1 回答 1

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
    }
}
于 2012-09-18T20:42:43.533 回答