Preallocazione dello spazio file in C#?
Domanda
Sto creando un'applicazione di download e desidero preallocare spazio sul harddrive per i file prima che vengano effettivamente scaricati in quanto potrebbero essere potenzialmente piuttosto grandi e a nessuno piace vedere "Questa unità è piena, per favore elimina alcuni file e riprova. " Quindi, in quella luce, ho scritto questo.
// Quick, and very dirty
System.IO.File.WriteAllBytes(filename, new byte[f.Length]);
Funziona, almeno finché non scarichi un file di diverse centinaia di MB, o potenzialmente anche GB e getti Windows in una frenesia frenetica se non cancelli completamente il file di paging e uccidi del tutto la memoria del tuo sistema.Ops.
Quindi, con un po’ più di illuminazione, ho iniziato con il seguente algoritmo.
using (FileStream outFile = System.IO.File.Create(filename))
{
// 4194304 = 4MB; loops from 1 block in so that we leave the loop one
// block short
byte[] buff = new byte[4194304];
for (int i = buff.Length; i < f.Length; i += buff.Length)
{
outFile.Write(buff, 0, buff.Length);
}
outFile.Write(buff, 0, f.Length % buff.Length);
}
Funziona, anche bene, e non soffre del paralizzante problema di memoria dell'ultima soluzione.Tuttavia è ancora lento, soprattutto su hardware più vecchio poiché scrive dati (potenzialmente GB) sul disco.
La domanda è questa:Esiste un modo migliore per ottenere la stessa cosa?Esiste un modo per dire a Windows di creare un file di dimensione x e allocare semplicemente lo spazio sul filesystem anziché scrivere effettivamente una tonnellata di dati.Non mi interessa affatto inizializzare i dati nel file (il protocollo che sto utilizzando - bittorrent - fornisce hash per i file che invia, quindi il caso peggiore per dati casuali non inizializzati è che ottengo una coincidenza fortunata e parte del file è corretta).
Soluzione
FileStream.SetLength è quello che vuoi.La sintassi:
public override void SetLength(
long value
)
Altri suggerimenti
Se devi creare il file, penso che probabilmente potresti fare qualcosa del genere:
using (FileStream outFile = System.IO.File.Create(filename))
{
outFile.Seek(<length_to_write>-1, SeekOrigin.Begin);
OutFile.WriteByte(0);
}
Dove lunghezza_da_scrivere sarebbe la dimensione in byte del file da scrivere.Non sono sicuro di avere la sintassi C# corretta (non su un computer per testarla), ma in passato ho fatto cose simili in C++ e ha funzionato.
Sfortunatamente, non puoi farlo davvero solo cercando fino alla fine.Ciò imposterà la lunghezza del file su qualcosa di enorme, ma potrebbe non allocare effettivamente i blocchi del disco per l'archiviazione.Quindi quando vai a scrivere il file, fallirà comunque.