Java FileChannel.size () против File.length () - после FileChannel.truncate () - PullRequest
4 голосов
/ 07 апреля 2019

Я думал об изменении этого вопроса в моей ситуации.Затем я решил, что моей ситуации нужен собственный вопрос и, надеюсь, ответы.После вызова 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()?Очистка метаданных файла будет в порядке, если только она не приводит к принудительной очистке содержимого файла.При очистке содержимого файла могут возникнуть ненужные операции ввода-вывода.

Ответы, указывающие на использование channelSize или fileLengthOpen или игнорирование проблемы, не будут приняты.У меня есть другой файл класса, который использует File.length(), чтобы определить длину файла.Передача channelSize или fileLengthOpen другому классу потребует передачи значения вверх по стеку на несколько кадров, а затем обратно на несколько кадров вниз.Если вы предлагаете мне использовать Files.size() для решения проблемы, объясните, почему.

Я не уверен, имеет ли это значение.Я использую Java 10 в Linux.(Да, я знаю, что Java 10 старая, но я застрял с ней, пока не смогу реализовать необходимые функции для обновления до Java 11.)

Редактировать: В прошлом многопоточные обновления файлов вызывалипроблемы.По этой причине я создал механизм блокировки файлов, чтобы только один поток во всем процессе мог работать исключительно с файлом (или несколько потоков могут читать файл).Кроме того, объект File, переданный моему truncate(), был создан вызывающим потоком и используется только этим потоком.Я могу гарантировать, что никакой другой поток в этом процессе не сможет работать с файлом на диске или объектом File.

Редактировать: Я изменил код для вызова Files.size() до и после channel.close().channel.size(), File.length() и Files.size() сообщают правильный размер при открытом channel.Сразу после channel.close(), File.length() и Files.size() в редких случаях исходная более длинная длина файла, а не усеченная более короткая длина.

1 Ответ

0 голосов
/ 01 мая 2019

Spin ждать, пока fileLengthClosed будет правильным.Вот код.

while (true)
{
   fileLengthClosed = file.length();

   if (fileLengthClosed == size)
      break;

   Thread.sleep(1);
}

Я запускал этот код в течение 3 недель, и не было никаких проблем.Одна из проблем заключается в том, что в случае изменения длины файла или отсутствия значения file.length() код тайм-аута отсутствует.

Это решение не отвечает, почему File.length() является неправильным с самого начала.Кроме того, вызов Thread.sleep() предполагает, что я действительно ожидаю завершения какой-либо другой операции, и мне действительно нужно заставить эту операцию завершиться или заблокировать эту операцию.Я не уверен, как заставить или заблокировать эту операцию.

...