Действительно, единственный «безопасный» способ сделать это - положиться на базовую файловую систему.
Просто:
public void saveThing(Serializable thing, String fileName) throws Exception {
String tempFileName = fileName + "_tmp";
File tempFile = new File(tempFileName);
FileOutputStream fos = new FileOutputStream(tempFile);
FileDescriptor fd = fos.getFD();
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(thing);
oos.flush();
fd.sync();
oos.close();
f.renameTo(fileName);
}
То, что происходит здесь, - сначала мы пишем файлво временный файл.Это обеспечивает успешную запись всего файла без повреждения исходного файла (например, если у вас заканчивается свободное место на диске, исходный файл будет сохранен, так как эта процедура не будет завершена).Однако, если эта подпрограмма завершится неудачно, временный временный файл останется, и его необходимо будет очистить позже.
После того, как мы записали файл, мы заставим ОС сбросить все ожидающие записи на фактический диск.Многие системы буферной файловой системы записывают в оперативную память и «в конечном итоге» записывают их на диск.Это по очевидным причинам производительности.Тем не менее, в случае сбоя системы или потери питания между моментом, когда вы закроете файл, и ОС решит сбросить записи, вы можете потерять данные.Эта синхронизация является ДОРОГОЙ операцией.
Наконец, когда мы уверены, что мы записали файл и что он записан на диск (насколько это возможно, мы все равно можем), мы переименовываем временный файл вфактическое имя файла.
Переименование файла в файловой системе является атомарной операцией.Это не может частично потерпеть неудачу.Это либо работает, либо нет.Если два файла находятся в одной файловой системе, переименование происходит практически мгновенно, поскольку оно просто обновляет некоторую информацию о файловой системе.Если они находятся в разных файловых системах, то новый файл должен быть сначала скопирован в новую файловую систему, а затем переименован.Я предполагаю, что это так, я никогда не проверял это.Я склонен придерживаться той же файловой системы и полностью избегать вопроса.
Этот процесс гарантирует, что файл будет обновлен, с правильным именем, полностью, "все сразу".Файл (с его правильным именем) никогда не «частично существует», что происходит, если бы вы просто перезаписали существующий файл.
Наконец, в Windows может возникнуть проблема, если есть конфликтисходный файл, так как Windows не удалит файл, открытый чем-то другим.Unix не имеет проблем с этим, но Windows делает.Таким образом, перед выполнением этой процедуры переименования необходимо с помощью некоторых внешних средств убедиться, что у вас есть единственный доступ к файлу.