Sto lavorando su un software server che necessita periodicamente di salvare i dati su disco. Devo assicurarmi che il vecchio file venga sovrascritto e che il file non possa essere danneggiato (ad esempio, solo parzialmente sovrascritto) in caso di circostanze impreviste.Salvataggio di file affidabile (File.Replace) in un ambiente occupato
ho adottato il seguente schema:
string tempFileName = Path.GetTempFileName();
// ...write out the data to temporary file...
MoveOrReplaceFile(tempFileName, fileName);
... dove MoveOrReplaceFile è:
public static void MoveOrReplaceFile(string source, string destination) {
if (source == null) throw new ArgumentNullException("source");
if (destination == null) throw new ArgumentNullException("destination");
if (File.Exists(destination)) {
// File.Replace does not work across volumes
if (Path.GetPathRoot(Path.GetFullPath(source)) == Path.GetPathRoot(Path.GetFullPath(destination))) {
File.Replace(source, destination, null, true);
} else {
File.Copy(source, destination, true);
}
} else {
File.Move(source, destination);
}
}
Questo metodo funziona bene fino a quando il server ha l'accesso esclusivo ai file. Tuttavia, File.Replace sembra essere molto sensibile all'accesso esterno ai file. Ogni volta che il mio software gira su un sistema con un antivirus o un sistema di backup in tempo reale, gli errori casuali File.Replace avvia popping up:
System.IO.IOException: impossibile rimuovere il file da sostituire.
Ecco alcune possibili cause che ho eliminato:
- file di Unreleased gestisce: usando() assicura che tutti gli handle di file vengono rilasciati al più presto possibile.
- Problemi di filettatura: lock() protegge tutti gli accessi a ciascun file.
- Diversi volumi del disco: File.Replace() ha esito negativo se utilizzato su volumi del disco. Il mio metodo lo controlla già e torna a File.Copy().
e qui ci sono alcuni suggerimenti che ho incontrato, e perché preferirei non li uso:
- Volume Shadow Copy Service: questo funziona solo fino a quando la terza problematica Anche i software di terze parti (backup e antivirus, ecc.) utilizzano VSS. L'utilizzo di VSS richiede tonnellate di P/Invoke e presenta problemi specifici della piattaforma.
- Blocco dei file: In C#, il blocco di un file richiede la gestione di un FileStream aperto. Manterrebbe fuori software di terze parti, ma 1) Non riesco ancora a sostituire il file usando File.Replace, e 2) Come ho detto sopra, preferisco scrivere prima su un file temporaneo, per evitare accidentalmente corruzione.
Apprezzerei qualsiasi input su come ottenere File.Replace per funzionare ogni volta o, più in generale, il salvataggio/sovrascrittura di file su disco in modo affidabile.
Si aspetta che "MoveOrReplaceFile" venga eseguito contemporaneamente (ovvero a cui si accede da più thread * dell'applicazione * o anche da più istanze dell'applicazione)? –
Il mio stesso codice non chiama MoveOrReplaceFile contemporaneamente, ma ci sono altri processi fuori dal mio controllo che potrebbero tentare di leggere il file. Questi accessi in lettura casuale sono ciò che causa il fallimento di File.Replace. – matvei