这些方法如何允许/导致数据在磁盘上丢失?
How are these methods allowing / causing data to be lost on disk?
我有一个程序会每隔一段时间(大约 15 秒)将其设置和数据写入磁盘。
如果程序是运行并且计算机突然关闭——例如,在墙上断电——不知何故我磁盘上的所有数据文件都变成了空文件。
这是我的代码,我认为我设计的代码是为了防止这种故障,但根据测试故障仍然存在:
SaveAllData -- 每隔一段时间调用一次,在调用 JavaFX.Application.stop() 时也会调用。
public void saveAllData () {
createNecessaryFolders();
saveAlbumsAndTracks();
saveSources();
saveCurrentList();
saveQueue();
saveHistory();
saveLibraryPlaylists();
saveSettings();
saveHotkeys();
}
CreateNecessaryFolders
private void createNecessaryFolders () {
if ( !playlistsDirectory.exists() ) {
boolean playlistDir = playlistsDirectory.mkdirs();
}
}
保存函数 -- 它们看起来都像这样
public void saveCurrentList () {
File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
currentListOut.writeObject( player.getCurrentList().getState() );
currentListOut.flush();
currentListOut.close();
Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING );
} catch ( Exception e ) {
LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
}
}
Github repository to commit where this problem exists. See Persister.java.
正如我所说,当突然断电时所有通过这种方法保存的设置文件都会被清空。这对我来说特别没有意义,因为它们是按顺序调用的,并且我确保在调用 move() 之前将文件写入磁盘并刷新。
知道这是怎么发生的吗?我想通过调用 flush、close,然后 move,我可以确保在覆盖旧数据之前将数据写入磁盘。不知何故,情况并非如此,但我一无所知。有什么建议么?
注意:这些文件仅由这些函数写入,仅由相应的load()函数读取。在我的程序中的任何其他地方都无法访问这些文件。
注意 2:我在 Ubuntu Linux 16.10 遇到了这个问题。我还没有在其他平台上测试过它。
将StandardCopyOption.ATOMIC_MOVE
添加到Files.move()
调用解决了问题:
public void saveCurrentList () {
File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
currentListOut.writeObject( player.getCurrentList().getState() );
currentListOut.flush();
currentListOut.close();
Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );
} catch ( Exception e ) {
LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
}
}
我有一个程序会每隔一段时间(大约 15 秒)将其设置和数据写入磁盘。
如果程序是运行并且计算机突然关闭——例如,在墙上断电——不知何故我磁盘上的所有数据文件都变成了空文件。
这是我的代码,我认为我设计的代码是为了防止这种故障,但根据测试故障仍然存在:
SaveAllData -- 每隔一段时间调用一次,在调用 JavaFX.Application.stop() 时也会调用。
public void saveAllData () {
createNecessaryFolders();
saveAlbumsAndTracks();
saveSources();
saveCurrentList();
saveQueue();
saveHistory();
saveLibraryPlaylists();
saveSettings();
saveHotkeys();
}
CreateNecessaryFolders
private void createNecessaryFolders () {
if ( !playlistsDirectory.exists() ) {
boolean playlistDir = playlistsDirectory.mkdirs();
}
}
保存函数 -- 它们看起来都像这样
public void saveCurrentList () {
File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
currentListOut.writeObject( player.getCurrentList().getState() );
currentListOut.flush();
currentListOut.close();
Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING );
} catch ( Exception e ) {
LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
}
}
Github repository to commit where this problem exists. See Persister.java.
正如我所说,当突然断电时所有通过这种方法保存的设置文件都会被清空。这对我来说特别没有意义,因为它们是按顺序调用的,并且我确保在调用 move() 之前将文件写入磁盘并刷新。
知道这是怎么发生的吗?我想通过调用 flush、close,然后 move,我可以确保在覆盖旧数据之前将数据写入磁盘。不知何故,情况并非如此,但我一无所知。有什么建议么?
注意:这些文件仅由这些函数写入,仅由相应的load()函数读取。在我的程序中的任何其他地方都无法访问这些文件。
注意 2:我在 Ubuntu Linux 16.10 遇到了这个问题。我还没有在其他平台上测试过它。
将StandardCopyOption.ATOMIC_MOVE
添加到Files.move()
调用解决了问题:
public void saveCurrentList () {
File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
currentListOut.writeObject( player.getCurrentList().getState() );
currentListOut.flush();
currentListOut.close();
Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );
} catch ( Exception e ) {
LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
}
}