我在考虑将这个问题转换成我的情况。然后我决定我的情况需要自己的问题和希望有答案。在调用FileChannel.truncate()
来缩小文件大小之后,我调用了FileChannel.size()
、关闭了FileChannel
,然后调用File.length()
。整个操作过程中,文件一直存在。FileChannel.size()
总是准确的。偶尔情况下,File.length()
会返回truncate()
之前的文件大小。
下面是展示情况的代码。
public static void truncate(File file, long size) throws IOException
{
FileChannel channel;
Path path;
long channelSize, fileLengthOpen, fileLengthClosed;
path = file.toPath();
channel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
try
{
channel.truncate(size);
channelSize = channel.size();
fileLengthOpen = file.length();
}
finally
{
channel.close();
}
fileLengthClosed = file.length();
if ((channelSize != size) || (fileLengthOpen != size) || (fileLengthClosed != size))
throw new IOException("The channel size or file length does not match the truncate size. Channel: " + channelSize + " - Open File: " + fileLengthOpen + " - Closed File: " + fileLengthClosed + " - Truncate: " + size);
}
在极少数情况下,代码会抛出IOException异常。channelSize == size且fileLengthOpen == size但fileLengthClosed != size。为什么fileLengthClosed != size?如何确保File.length()与FileChannel.size()匹配?刷新文件的元数据是可以的,只要不强制刷新文件的内容即可。刷新文件的内容会产生不必要的文件I/O。
不接受建议我使用channelSize或fileLengthOpen或忽略该问题的答案。我有另一个类文件使用File.length()来确定文件的长度。将channelSize或fileLengthOpen传递给另一个类需要将该值向上传递几个帧,然后再向下传递多个帧。如果您建议我使用Files.size()来解决该问题,请说明原因。
我不确定这是否重要。我在Linux上运行Java 10。(是的,我知道Java 10很老,但在我实施升级到Java 11所需的功能之前,我被卡住了。)
编辑:过去,在文件上的多线程更新会造成问题。因此,我创建了文件锁定机制,以便整个过程中只有1个线程可以独立操作文件(或多个线程可以读取文件)。此外,传递给我的truncate()的File对象由调用线程创建,仅由该线程使用。我可以保证进程中没有其他线程可以操作磁盘上的文件或File对象。
编辑:我更改了代码以在channel.close()之前和之后调用Files.size()。channel.size()、File.length()和Files.size()在channel打开时报告正确的大小。在channel.close()之后立即,File.length()和Files.size()偶尔会出现原始更长文件长度而不是截断的较短长度。
Files.size()
呢?File
类应该被允许安息了。你试过用Files.size()
来解决这个问题吗? - RealSkepticFile.length()
。如果我能证明它可以解决问题,我将对代码进行更改以使用Files.size()
。我已经修改了truncate()
,在关闭FileChannel
之前和之后检查Files.size()
,然后观察结果......可能需要几天时间才能复现这个问题。 - NathanFiles.size()
后更新了问题。Files.size()
与File.length()
存在相同的问题。 - Nathan