Как безопасно сохранить данные в файл, который уже существует в C #? У меня есть некоторые данные, которые сериализуются в файл, и я почти уверен, что не стоит сохранять их непосредственно в файле, потому что, если что-то пойдет не так, файл будет поврежден, а предыдущая версия потеряна.
Итак, это то, чем я занимаюсь до сих пор:
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 случайными цифрами.
Я не понимаю, как это могло испортить исходный файл, если ОС не работает. Это довольно близко к ответу Ханса, за исключением того, что я сначала сохраняю файл во временный файл, так что, если что-то пойдет не так при сериализации, мне не нужно переименовывать файл обратно в его первоначальное имя, что также может пойти не так. Пожалуйста! дайте мне знать, если найдете какой-либо недостаток.