Как вы безопасно сохраняете данные в файл, который уже существует на С#? У меня есть некоторые данные, которые сериализованы в файл, и я уверен, что это не очень хорошая идея для безопасного обращения к файлу, потому что, если что-то пойдет не так, файл будет поврежден, а предыдущая версия будет потеряна.
Так вот что я делаю до сих пор:
string tempFile = Path.GetTempFileName();
using (Stream tempFileStream = File.Open(tempFile, FileMode.Truncate))
{
SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
xmlFormatter.Serialize(tempFileStream, Project);
}
if (File.Exists(fileName)) File.Delete(fileName);
File.Move(tempFile, fileName);
if (File.Exists(tempFile)) File.Delete(tempFile);
Проблема заключается в том, что когда я пытался сохранить файл, который был в моем Dropbox, иногда я получал исключение, говорящее, что он не может сэкономить файл, который уже существует. По-видимому, первый File.Delete(fileName);
не удалил файл сразу, а после немного. Поэтому я получил исключение в File.Move(tempFile, fileName);
, потому что файл существовал, а затем файл удалился, и мой файл потерялся.
Я использовал другие приложения с файлами в своем Dropbox, и каким-то образом им не удалось их испортить. Когда я пытаюсь сохранить файл в папке Dropbox, иногда я получаю сообщение о том, что файл используется или что-то вроде этого, но у меня никогда не было проблемы с удаляемым файлом.
Итак, какова была бы эталонная/лучшая практика здесь?
Хорошо, вот что я придумал после прочтения всех ответов:
private string GetTempFileName(string dir)
{
string name = null;
int attempts = 0;
do
{
name = "temp_" + Player.Math.RandomDigits(10) + ".hsp";
attempts++;
if (attempts > 10) throw new Exception("Could not create temporary file.");
}
while (File.Exists(Path.Combine(dir, name)));
return name;
}
private void SaveProject(string fileName)
{
bool originalRenamed = false;
string tempNewFile = null;
string oldFileTempName = null;
try
{
tempNewFile = GetTempFileName(Path.GetDirectoryName(fileName));
using (Stream tempNewFileStream = File.Open(tempNewFile, FileMode.CreateNew))
{
SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
xmlFormatter.Serialize(tempNewFileStream, Project);
}
if (File.Exists(fileName))
{
oldFileTempName = GetTempFileName(Path.GetDirectoryName(fileName));
File.Move(fileName, oldFileTempName);
originalRenamed = true;
}
File.Move(tempNewFile, fileName);
originalRenamed = false;
CurrentProjectPath = fileName;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if(tempNewFile != null) File.Delete(tempNewFile);
if (originalRenamed) MessageBox.Show("'" + fileName + "'" +
" have been corrupted or deleted in this operation.\n" +
"A backup copy have been created at '" + oldFileTempName + "'");
else if (oldFileTempName != null) File.Delete(oldFileTempName);
}
}
Player.Math.RandomDigits
- это лишь небольшая функция, которую я создал, которая создает строку с n случайными цифрами.
Я не вижу, как это может испортить исходный файл, если ОС не собирается wacko. Это довольно близко к ответу Ханса, за исключением того, что я сначала сохраняю файл во временном файле, чтобы, если что-то пошло не так, когда сериализуется, мне не нужно переименовывать файл обратно к нему с оригинальным именем, что также может пойти не так. Пожалуйста! сообщите мне, если вы обнаружите недостатки.