2010-06-29 2 views
7

Ho un programma che apre un file binario di grandi dimensioni, aggiunge una piccola quantità di dati e chiude il file.Come evitare un I/O file di rete eccessivo durante l'aggiunta a un file di grandi dimensioni con .NET?

FileStream fs = File.Open("\\\\s1\\temp\\test.tmp", FileMode.Append, FileAccess.Write, FileShare.None); 
fs.Write(data, 0, data.Length); 
fs.Close(); 

Se test.tmp è 5MB prima questo programma è eseguito e la schiera di dati è di 100 byte, questo programma causerà oltre 5 MB di dati da trasmettere attraverso la rete. Mi sarei aspettato che i dati già nel file non venissero trasmessi attraverso la rete poiché non li sto leggendo o scrivendo. C'è un modo per evitare questo comportamento? Questo lo rende tremendamente lento da aggiungere a file molto grandi.

+1

Hai provato invece il metodo FileStream.Seek? – ChrisW

+2

È attivo uno scanner antivirus che esegue un controllo all'accesso? –

+0

Potresti aggiungere alcune informazioni sul tuo obiettivo finale (ad esempio un sistema di registrazione o uno strumento di reporting dei dati) poiché gli utenti potrebbero avere alcuni suggerimenti che potresti non aver considerato. –

risposta

2

0xA3 ha fornito la risposta in un comunicato di cui sopra. Le scarse prestazioni erano dovute a una scansione dei virus in accesso. Ogni volta che il mio programma apriva il file, lo scanner antivirus leggeva l'intero contenuto del file per verificare la presenza di virus anche se il mio programma non leggeva alcun contenuto esistente. La disattivazione della scansione dei virus in accesso ha eliminato l'I/O di rete eccessivo e le prestazioni scadenti.

Grazie a tutti per i vostri suggerimenti.

0

È possibile memorizzare i dati in un buffer locale e periodicamente (molto meno spesso di adesso) aggiungere al file di grandi dimensioni. Ciò farebbe risparmiare su un mucchio di trasferimenti di rete ma ... Ciò aumenterebbe anche il rischio di perdere quella cache (e i tuoi dati) nel caso in cui la tua app si arresti in modo anomalo.

La registrazione (se è ciò che è) di questo tipo è spesso memorizzata in un db. L'utilizzo di un RDBMS decente consentirebbe di pubblicare quei 100 byte di dati molto frequentemente con un sovraccarico minimo. L'avvertenza c'è la manutenzione di un RDBMS.

-3

ho fatto qualche googling e stava guardando più a come leggere file di dimensioni eccessive in modo rapido e trovato questo link http://www.4guysfromrolla.com/webtech/010401-1.shtml

La parte più interessante ci sarebbe la parte che riguarda la lettura di byte: Oltre al ReadAll più comunemente usata e Metodi ReadLine, l'oggetto TextStream supporta anche un metodo Read (n), dove n è il numero di byte nel file/flusso di testi in questione. Istanziando un oggetto aggiuntivo (un oggetto file), possiamo ottenere la dimensione del file da leggere e quindi utilizzare il metodo Read (n) per sfogliare il nostro file. Come si è visto, il metodo "read byte" è estremamente veloce in confronto:

const ForReading = 1 
const TristateFalse = 0 
dim strSearchThis 
dim objFS 
dim objFile 
dim objTS 
set objFS = Server.CreateObject("Scripting.FileSystemObject") 
set objFile = objFS.GetFile(Server.MapPath("myfile.txt")) 
set objTS = objFile.OpenAsTextStream(ForReading, TristateFalse) 

strSearchThis = objTS.Read(objFile.Size) 

if instr(strSearchThis, "keyword") > 0 then 
Response.Write "Found it!" 
end if 

Questo metodo potrebbe poi essere usato da voi per andare alla fine del file e aggiungendo manualmente invece di caricare l'intero file in modalità append con un filestream.

+0

-1: hai notato che questo era un articolo del 2001, per VBScript, non per .NET? –

0

Se si dispone dell'accesso al sistema o di un amministratore amichevole per la macchina che ospita effettivamente il file, è possibile creare un piccolo programma di ascolto che si trova all'altra estremità.

Si effettua una chiamata passando solo i dati da scrivere e lo fa in locale, evitando il traffico di rete aggiuntivo.

0

L'oggetto File in .NET ha alcuni metodi statici per gestire questo tipo di cose. Vorrei suggerire cercando:

File file = File.AppendAllText("FilePath", "What to append", Encoding.UTF8); 

Quando si riflette questo metodo si scopre che si sta usando:

using (StreamWriter writer = new StreamWriter(path, true, encoding)) 
{ 
    writer.Write(contents); 
} 

Questo metodo StreamWriter dovrebbe consentono di aggiungere semplicemente qualcosa fino alla fine (almeno questa è la metodo che ho visto utilizzato in ogni istanza di registrazione che ho incontrato finora).

+0

Hai testato le prestazioni di questo? –

+1

AppendAllText restituisce void, non File :) http://msdn.microsoft.com/en-us/library/system.io.file.appendalltext.aspx –

1

ho trovato this on MSDN (CreateFile viene chiamato internamente):

Quando un'applicazione crea un file in una rete, è meglio usare GENERIC_READ | GENERIC_WRITE per dwDesiredAccess che utilizzare GENERIC_WRITE da solo. Il codice risultante è più veloce, perché il redirector può utilizzare il gestore cache e inviare meno SMB con più dati.Questa combinazione evita anche un problema in cui la scrittura su un file attraverso una rete può occasionalmente restituire ERROR_ACCESS_DENIED.

Utilizzando riflettore, FileAccess mappe per dwDesiredAccess, così sembrerebbe suggerire utilizzando FileAccess.ReadWrite invece di FileAccess.Write.

ho idea se questo aiuterà :)

0

Scrivere i dati in file separati, poi unirsi a loro (farlo sulla macchina che ospita se possibile) solo quando è necessario.

+0

Dico questo, perché la "risposta lunga" è davvero lunga , http://en.wikipedia.org/wiki/Server_Message_Block e non c'è modo di aggirarlo. È una limitazione del sistema di condivisione file di Windows. – rwong