Недавно столкнулся с тем же требованием. Фактически ранее я использовал для создания нового FileStream
внутри оператора using
и перезаписи предыдущего файла. Похоже на простую и эффективную вещь.
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
Однако я столкнулся с проблемами блокировки, когда какой-то другой процесс блокирует целевой файл. Пытаясь помешать этому, я повторил попытку записи несколько раз, прежде чем отправить ошибку в стек.
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);
}
}
Казалось, это работает почти для всех. Затем появился этот проблемный компьютер и заставил меня постоянно поддерживать блокировку файла. Таким образом, вместо попытки записать файл в случае, если он уже заблокирован, я теперь проверяю, получаю и удерживаю ли поток открытым, чтобы не было проблем с блокировкой при последующих записях.
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);
}
}
Теперь, когда я пишу файл, позиция FileStream
должна быть сброшена в ноль, как сказал Аарона. Я решил «очистить» файл, вызвав _stream.SetLength(0)
. Казалось, самый простой выбор. Затем с помощью нашего выбранного сериализатора, protobuf-net
Марка Грэвелла, сериализуйте значение в поток.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
В большинстве случаев это прекрасно работает, и файл полностью записывается на диск. Однако в некоторых случаях я наблюдал, что файл не сразу записывается на диск. Чтобы поток был очищен и файл был полностью записан на диск, мне также нужно было вызвать _stream.Flush(true)
.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
_stream.Flush(true);