Java FileChannel.size() vs File.length() - 在 FileChannel.truncate() 之后

Posted

技术标签:

【中文标题】Java FileChannel.size() vs File.length() - 在 FileChannel.truncate() 之后【英文标题】:Java FileChannel.size() vs File.length() - After FileChannel.truncate() 【发布时间】:2019-04-07 15:17:42 【问题描述】:

我正在考虑将this question 更改为我的情况。然后我决定我的情况需要自己的问题并希望得到答案。调用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);

在极少数情况下,代码会抛出 IOExceptionchannelSize == sizefileLengthOpen == sizefileLengthClosed != size

为什么fileLengthClosed != size?如何确保File.length() 匹配FileChannel.size()?只要不强制刷新文件的内容,刷新文件的元数据就可以了。刷新文件内容会导致不需要的文件 I/O。

告诉我使用channelSizefileLengthOpen 或忽略问题的答案将不被接受。我有另一个使用File.length() 来确定文件长度的类文件。将channelSizefileLengthOpen 传递给另一个类需要将值向上传递几帧,然后再向下传递几帧。如果您建议我使用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()是否有这个问题? 已知 Windows 在文件打开时不会更新文件元数据。 我的代码库中有大约 90 个地方使用了File.length()。如果我能证明它解决了问题,我会将代码更改为Files.size()。我将truncate() 更改为在关闭FileChannel 之前和之后检查Files.size(),我会看看会发生什么……重现问题可能需要几天时间。 不幸的是,该问题不会在 Windows 上重现。但是,这并不能说明太多,因为该问题在 Linux 上不会经常重现。 @RealSkeptic 我在使用Files.size() 后更新了问题。 Files.size()File.length()有同样的问题。 【参考方案1】:

旋转等待fileLengthClosed 正确。这是代码。

while (true)

   fileLengthClosed = file.length();

   if (fileLengthClosed == size)
      break;

   Thread.sleep(1);

我已运行此代码 3 周,没有出现任何问题。一个问题是在文件长度被修改或file.length() 永远不会更新的情况下没有超时代码。

这个解决方案首先没有回答为什么File.length() 不正确。另外,调用Thread.sleep() 表明我真的在等待其他一些操作完成,我真的应该强制该操作完成或阻止该操作。我不确定如何强制或阻止该操作。

【讨论】:

以上是关于Java FileChannel.size() vs File.length() - 在 FileChannel.truncate() 之后的主要内容,如果未能解决你的问题,请参考以下文章

Java JNI 错误 java.lang.UnsatisfiedLinkError: xxxx()V

java Vector 怎么用一个Vector来给一个一维数组赋值呢?

java Vector 怎么用一个Vector来给一个以维数组赋值呢?

在 Java tensorflow v.1.2.0 中使用 Python tensorflow v.0.9.0 加载预训练模型

V语言横空出世,C/C++/Java/Python/Go地位不保

Java基础知识--HashMap的理解