Recientemente se presentó el mismo requisito. De hecho, anteriormente, solía crear un nuevo FileStream
dentro de una declaración using
y sobrescribir el archivo anterior. Parece la cosa simple y efectiva para hacer.
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
Sin embargo, me encontré con problemas de bloqueo donde algún otro proceso está bloqueando el archivo de destino. En mi intento de frustrar esto, reintenté la escritura varias veces antes de subir el error a la pila.
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);
}
}
Eso parecía funcionar para casi todo el mundo. Luego apareció esa máquina problemática y me obligó a seguir el camino de mantener un bloqueo en el archivo todo el tiempo.Entonces, en lugar de volver a intentar escribir el archivo en el caso de que ya esté bloqueado, ahora me estoy asegurando de mantener y mantener abierta la ruta para que no haya problemas de bloqueo con las escrituras posteriores.
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);
}
}
Ahora, cuando escribo el archivo de la posición FileStream
se debe restablecer a cero, como se dijo Aaronaught. Opté por "borrar" el archivo llamando al _stream.SetLength(0)
. Parecía la elección más simple. Luego, utilizando nuestro serializador de elección, protobuf-net
de Marc Gravell, serialice el valor de la transmisión.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
Esto funciona bien la mayor parte del tiempo y el archivo está completamente escrito en el disco. Sin embargo, en algunas ocasiones he observado que el archivo no se escribe inmediatamente en el disco. Para garantizar que la transmisión se vacíe y el archivo esté completamente escrito en el disco, también tuve que llamar al _stream.Flush(true)
.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
_stream.Flush(true);
¿Cuál sería su elección entonces? No quiero permitir que dos usuarios abran el archivo al mismo tiempo pensando que ambos tienen acceso de escritura y cada uno sobreescribe los guardados del otro. –
Una de las respuestas más comunes es crear un "archivo de bloqueo" de longitud cero. Esto se puede combinar con mantener un 'FileStream' abierto indefinidamente, por supuesto, pero muchas aplicaciones optan solo por el archivo de bloqueo, ya que puede ser anulado si es necesario. Supongo que depende de la naturaleza de tu aplicación y del entorno para compartir. Tal vez sea la mejor opción. – Aaronaught
Set-length (0) parece hacer lo que intento hacer. –