Gleichzeitiges Beschreiben und Lesen einer Datei  
Frank Dzaebel, erstellt am: 17.09.06, zuletzt geändert:  17.09.06
Kategorie: I/O, .NET-Version: 2.0, [Download]

In folgendem Beispiel-Projekt wird das Verfahren des gemeinsamen Lesens und Schreibens einer  Datei verdeutlicht. Ein umständliches Neuanlegen einer zweiten und späteres ineffizientes Rückkopieren ist so nicht nötig. Eine Voraussetzung ist, dass sich die Zeilen-Längen dabei nicht vergrössern. Die Technik geht über einen gleichzeitig geöffneten StreamReader und StreamWriter, die dann einen gemeinsamen BaseStream benutzen, dessen Position auf gewünschte Werte gesetzt werden kann.



using System;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace ConcurrentReadWrite
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    string path = "Datei.csv";

    private void btnStart_Click(object sender,EventArgs e)
    {
      Cursor = Cursors.WaitCursor;
      FillFileWithTestdata(path);
      FileStream fs = File.Open(path,FileMode.Open,FileAccess.ReadWrite,FileShare.ReadWrite);
      StreamWriter sw = new StreamWriter(fs,Encoding.Default);
      StreamReader sr = new StreamReader(fs,Encoding.Default);
      sw.AutoFlush = true; long aktPos = 0; bool firstTime = true;
      long bufferLen = 0; int lenReturn = "\r\n".Length;

      while (aktPos < fs.Length)
      {
        string line = sr.ReadLine(); int lineLen = line.Length;
        if (firstTime)
        {
          bufferLen = sw.BaseStream.Position;
          sw.BaseStream.Position = 0;  firstTime = false;
        }
        int diff = (int)(bufferLen - aktPos);
        if (lineLen >= diff)
        {
          if (diff > 0) line = line.Substring(diff);
          bufferLen = sr.BaseStream.Position;
          sr.BaseStream.Position = aktPos;
        }
        line = Regex.Replace(line, "^.", "*");  
        sw.WriteLine(line);
        aktPos += (line.Length + lenReturn);
      }
      sw.Close();
      Cursor = Cursors.Default;
      grpNachher.Text = "Nachher (ein * wurde in allen Zeilen in Spalte1 'on the fly' ersetzt)";
      txbNachher.Text = File.ReadAllText(path);
    }

    /// <summary>Füllen von Beispiel-Daten in die Datei.</summary>
    private void FillFileWithTestdata(string path)
    {
      StreamWriter sw = new StreamWriter(path,false,Encoding.Default);
      sw.AutoFlush = true;
      int step = 5;
      int maxNumber = 3000;
      Random rnd = new Random(DateTime.Now.Millisecond);
      int minRandom = 1; int maxRandom = 10;
      int padding = rnd.Next(minRandom,maxRandom);

      for (int i = 1; i <= maxNumber; i += step)
      {
        for (int j = 0; j < step; j++)
        {
          sw.Write((i + j).ToString().PadLeft(rnd.Next(minRandom,maxRandom),'0'));
          if (j != step - 1) sw.Write(", ");
        }
        sw.WriteLine();
      }
      sw.Close();
      txbVorher.Text = File.ReadAllText(path);
    }
  }
}