2015-11-11 14 views
7

ho bisogno di manipolare il contenuto di un file:C# file di sovrascrittura con StreamWriter creato da FileStream

FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);    
StreamReader sr = new StreamReader(fs); 
StreamWriter sw = new StreamWriter(fs); 
newString = someStringTransformation(sr.ReadToEnd()); 
sw.Write(newString); 
fs.flush(); 
fs.Close(); 

Tuttavia quanto sopra aggiunge i newString invece di sovrascrivere il file con le nuove modifiche. Deve essere fatto in modo che nessun'altra applicazione possa accedere al file tra la lettura di una scrittura e questo è il motivo per cui sto creando il lettore e il writer da un oggetto FileStream.

So che è possibile creare uno StreanWriter con il secondo parametro impostato su false come descritto here. Tuttavia, quando si crea StreamWriter come sopra, questo non sembra essere uno dei parametri.

+1

Prova il lavaggio del torrente e riposizionamento indietro all'inizio del file, quindi scrivere, quindi lavare lo scrittore, quindi troncare il file. –

+0

Un altro modo è creare un altro file temporaneo, salvare tutti i nuovi contenuti in quel file, quindi eliminare quello vecchio e rinominare quello nuovo. –

+1

Quello che stai cercando di fare non ha senso, non hai alcuna protezione contro un altro processo che legge il file un microsecondo prima di aprire il file. –

risposta

9

Il problema che si verifica è che la lettura dallo stream avanza alla fine del file. Ulteriori scritture verranno poi aggiunte.

Ciò consentirà una sovrascrittura completa.

using(FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None) 
{    
    StreamReader sr = new StreamReader(fs); 
    StreamWriter sw = new StreamWriter(fs); 
    newString = someStringTransformation(sr.ReadToEnd()); 

    // discard the contents of the file by setting the length to 0 
    fs.SetLength(0); 

    // write the new content 
    sw.Write(newString); 
} 

Perché utilizzare SetLength? Il tuo nuovo contenuto potrebbe essere più breve della stringa esistente! L'ultima cosa che vuoi è il vecchio contenuto alla fine del tuo file.

1

Ci sono diversi passaggi che dovete prendere qui, ma permettetemi di fare le mie supposizioni chiaro:

È necessario mantenere il file aperto e bloccato durante l'intera operazione per impedire ad altri di accedere al file durante questo periodo .

Detto questo, ecco cosa devi fare:

  1. Hai bisogno di leggere i contenuti che utilizzano il StreamReader, come hai fatto
  2. È necessario riposizionare il flusso sottostante torna a l'inizio, la sua posizione è stata cambiata leggendo attraverso il lettore
  3. È necessario scrivere i contenuti trasformati attraverso il StreamWriter, come hai fatto
  4. È necessario svuotare e writer a causa del passaggio successivo
  5. È necessario troncare il flusso/file sottostante nella posizione corrente, per gestire una trasformazione che accorcia i contenuti.

Il codice per tutto questo potrebbe apparire come questo programma LINQPad:

void Main() 
{ 
    const string filePath = @"d:\temp\test.txt"; 
    var encoding = Encoding.UTF8; 
    using (var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) 
    using (var reader = new StreamReader(stream, encoding)) 
    using (var writer = new StreamWriter(stream, encoding)) 
    { 
     // Read 
     var contents = reader.ReadToEnd(); 

     // Transform 
     var transformedContents = contents.Substring(0, Math.Max(0, contents.Length - 1)); 

     // Write out transformed contents from the start of the file 
     stream.Position = 0; 
     writer.Write(transformedContents); 
     writer.Flush(); 

     // Truncate 
     stream.SetLength(stream.Position); 
    } 
} 
1

Che cosa si potrebbe fare è riposizionando i corsi d'acqua e la rimozione anche dati nel buffer per essere sicuri che nulla si mette di mezzo. Prendendo il tuo esempio:

FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);    
StreamReader sr = new StreamReader(fs); 
StreamWriter sw = new StreamWriter(fs); 
newString = someStringTransformation(sr.ReadToEnd()); 

    sr.Position = 0; 
    sr.DiscardBufferedData(); 

    sw.Position = 0; 

sw.Write(newString); 
fs.flush(); 
fs.Close(); 

se i nuovi dati è inferiore alla vecchia dati si avrebbe bisogno di troncare i dati rimanenti. Utilizzando sw.SetLength(newString.Length);.

1

È possibile evitare questi basso livello Stream 's ed i loro Reader/Writer s utilizzando Linq:

File.WriteAllText(filePath, someStringTransformation(File.ReadAllText(filePath))); 
Problemi correlati