Recentemente si è imbattuto nello stesso requisito. Infatti, in precedenza, ero solito creare un nuovo FileStream
all'interno di un'istruzione using
e sovrascrivere il file precedente. Sembra la cosa semplice ed efficace da fare.
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
Tuttavia, ho riscontrato problemi di blocco in cui un altro processo blocca il file di destinazione. Nel mio tentativo di contrastare ciò, ho ripetuto la scrittura diverse volte prima di spingere l'errore in cima allo stack.
int attempt = 0;
while (true)
{
try
{
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
break;
}
catch (IOException)
{
// could be locked by another process
// make up to X attempts to write the file
attempt++;
if (attempt >= X)
{
throw;
}
Thread.Sleep(100);
}
}
Sembrava funzionare per quasi tutti. Poi quella macchina del problema arrivò e mi costrinse a seguire il percorso di mantenere un blocco sul file per tutto il tempo.Quindi, invece di riprovare a scrivere il file nel caso in cui sia già bloccato, ora mi sto assicurando di ottenere e tenere aperto lo stream in modo che non ci siano problemi di blocco con le scritture successive.
int attempt = 0;
while (true)
{
try
{
_stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
break;
}
catch (IOException)
{
// could be locked by another process
// make up to X attempts to open the file
attempt++;
if (attempt >= X)
{
throw;
}
Thread.Sleep(100);
}
}
Ora quando scrivo il file nella posizione FileStream
deve essere resettato a zero, come ha detto Aaronaught. Ho deciso di "cancellare" il file chiamando lo _stream.SetLength(0)
. Sembrava la scelta più semplice. Quindi, utilizzando il nostro serializzatore di scelta, Marc Gravell's protobuf-net
, serializza il valore nello stream.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
Questo funziona bene la maggior parte del tempo e il file è completamente scritto sul disco. Tuttavia, in alcune occasioni ho osservato che il file non viene immediatamente scritto sul disco. Per garantire che il flusso venga svuotato e che il file sia completamente scritto su disco, dovevo chiamare anche _stream.Flush(true)
.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
_stream.Flush(true);
Quale sarebbe la vostra scelta allora? Non voglio consentire a due utenti di aprire il file allo stesso tempo pensando di avere entrambi accesso in scrittura e di sovrascrivere i salvataggi dell'altro? –
Una delle risposte più comuni è creare un "file di blocco" a lunghezza zero. Questo può essere combinato mantenendo un file "FileStream" aperto a tempo indeterminato, ovviamente, ma molte app scelgono solo il file di blocco perché può essere sovrascritto se necessario. Immagino dipenda dalla natura della tua app e dell'ambiente di condivisione - forse è davvero l'opzione migliore. – Aaronaught
Set-length (0) sembra fare ciò che sto cercando di fare. –