Методы чтения Java InputStream, возвращающие символы ASCII 'NUL' для файла в месте монтирования NFS

У меня есть процесс Java, который читает данный файл с помощью Java RandomAccessFile и выполняет некоторую обработку на основе содержимого файла. Этот файл представляет собой файл журнала, который обновляется другим процессом Java. Процесс Java, который читает файл, находится на другом компьютере и имеет настройку монтирования NFS для доступа к файлу на удаленном сервере. В основном процесс, который читает файл, будет опрашивать изменения в файле на основе длины файла и положения RandomAccessFile и вызывать метод обработчика для каждого встречающегося байта. Проблема в том, что я иногда получаю символы ASCII 'NUL', возвращаемые из метода чтения RandomAccessFile.

int charInt = read();

то есть charInt в некоторых случаях возвращает 0, а через некоторое время возвращает допустимые символы. Но тогда мне не хватает символов во время чтения потока в NUL

Я попытался использовать http://commons.apache.org/io/apidocs/org/apache/commons/io/input/Tailer.html, где я получаю уведомления о каждой строке. но затем в этих строках я иногда замечаю символы ASCII NUL. Я также прошел через Java IO реализацию хвоста unix/linux - f - мой java-процесс чем-то похож, но потом я начинаю думать, что проблема связана с монтированием NFS или каким-то ошибочным вводом-выводом java при попытке чтения с монтирования NFS. Я провел некоторое тестирование чтения из обычного файла (который не находится в монтировании NFS) и имел процесс, который постоянно записывает в него. Все эти испытания прошли успешно. Я также попробовал java BufferedReader, поскольку поток файлов на самом деле является потоком символов, хотя я могу рассматривать его как поток байтов. Тем не менее я получаю символы NUL.

не уверен, будет ли это иметь значение - монтирование NFS доступно только для чтения (ro). Ценим любую помощь в этом. Спасибо.

Я также пробовал следующее:

FileWriter fileWriter;
    try {
        fileWriter = new FileWriter("<OUT_FILE>", true);
    } catch (IOException e) {
        throw new RuntimeException("Exception while creating file to write sent messages ", e);
    }
    BufferedWriter bufWriter = new BufferedWriter(fileWriter);

    Runtime r = Runtime.getRuntime();
    Process p = r.exec("tail -f <PATH_TO_IN_FILE>");
    Scanner s = new Scanner(p.getInputStream());
    while (s.hasNextLine()) {     
        String line = s.nextLine(); 
        bufWriter.write(line);
        bufWriter.write(System.getProperty("line.separator"));
        bufWriter.flush();

    }
    bufWriter.close();                               

и все же я получаю символы NUL. Здесь я записываю прочитанные строки в файл, чтобы затем сравнить файл IN и файл OUT. Я вижу, что в одном случае строки пропускаются (с символами NUL). все остальные строки сравниваются нормально, поэтому из примерно 13000 строк мы видим несоответствие примерно в 100 строках. Еще одна странность заключается в том, что у меня было меньше работы, и я также вижу здесь символы NUL, они в основном в форме ^C^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@ ^@^@^@^@^@^@^@^@, а затем допустимые строки. еще одна вещь, которую я заметил в то время, когда строки были пропущены, файл очень быстро обновлялся в процессе записи, поэтому в основном сообщение xml было записано в файл по адресу 20110729 13:44:06.070097, а затем следующее сообщение по адресу 20110729 13. :44:06.100007. строки были пропущены из этого второго сообщения xml. дополнительные выводы: путь к файлу, по которому мы считываем файлы, находится в общем NAS.


person gregoryp    schedule 25.07.2011    source источник


Ответы (2)


Я понимаю, что этому вопросу уже больше года, но я добавлю к нему то, что знаю, на случай, если другие с этой проблемой наткнутся на него, как и я.

Символы NUL, описанные в этом вопросе, появляются из-за асинхронной записи в считываемый файл. В частности, пакеты данных от удаленного модуля записи файлов поступили не по порядку, а буфер NAS зафиксировал более поздний пакет и дополнил область неполученных данных символами NUL. Когда отсутствующий пакет получен, буфер NAS фиксирует его, перезаписывая эти нулевые символы.

В приложении, где мы впервые столкнулись с этим, мы читаем файл построчно и отслеживаем номер последней успешно прочитанной строки (поэтому мы можем остановиться в любой момент и начать снова с того места, на котором остановились). Наше временное решение для решения этой проблемы состоит в том, чтобы просто проверять наличие «\0» при каждом чтении и, когда он встречается, закрывать файл, ждать 1 секунду и снова открывать файл, ставя в очередь до того места, где мы остановились. Обычно к тому времени, когда мы снова читаем строку, фактический текст уже зафиксирован.

Хотя закрытие и повторное открытие файла может показаться драматическим, восстановление без этого проблематично. Вы не можете пометить/сбросить BufferedReader, чтобы решить эту проблему, потому что после того, как символы будут считаны в буфер читалки, они не будут повторно считаны из файла, а только извергаются каждый раз, когда вы пытаетесь прочитать снова.

Получить базовый FileChannel, а также прочитать и установить position() также не удается, потому что ваша позиция в файле включает в себя символы, считанные в буфер, которые вы, возможно, еще не видели, и в конечном итоге вы пропустите эти невидимые данные.

Мы тестируем решение, в котором мы расширили класс InputStreamReader и перезаписали метод read(char[], int, int), чтобы использовать файловый канал для получения позиции перед каждым чтением, вызвать метод чтения суперкласса, проверить \0 и сбросить позиция файлового канала, если она найдена, возвращая 0 как количество прочитанных символов.

person Gregg Dale    schedule 06.09.2012

Вы пробовали что-то вроде этого:

  BufferedReader input = new BufferedReader(new FileReader(args[0]));
  String currentLine = null;

  while (true) {

    if ((currentLine = input.readLine()) != null) {
      System.out.println(currentLine);
      continue;
    }
    try {
      Thread.sleep(sleepTime);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      break;
    }
   }

Если ничего не может быть прочитано из файла, то currentLine будет нулевым...

Я сомневаюсь, что есть конкретная проблема NFS + Java, тот факт, что вы получаете доступ к файлу через NFS, должен быть неизвестен виртуальной машине.

person Angel O'Sphere    schedule 25.07.2011
comment
благодаря. да, я пробовал это - проблема в том, что в некоторых случаях я получаю символы NUL в напечатанных строках, когда я ожидаю, что они будут действительными. Кроме того, иногда возвращаемые строки становятся большими, потому что поток не может прочитать символы LF или CR и вместо этого считывает символы NUL. - person gregoryp; 26.07.2011
comment
Тогда это может быть проблема с кодировкой, если вы откроете файл, вы можете сказать, является ли он, например. utf-8, также, если это действительно необходимо, вы можете установить окончания строк. Проблема может возникнуть из-за того, что операционная система, в которой работает ваш код Java, отличается от той, в которой он записывается в смонтированный файл NFS. - person Angel O'Sphere; 26.07.2011
comment
Я не контролирую процесс, который записывает в файл. Операционные системы одинаковые - только что проверил. Не уверен, какую кодировку использует JVM. Я считаю, что это должно быть в каком-то системном свойстве. мне не удалось воспроизвести проблему, когда процесс записи выполнялся на той же машине, что и процесс чтения. Но проблема возникла, когда запись была сделана на удаленном сервере. Кроме того, частота обновления/записи файла была одинаковой в обоих сценариях. - person gregoryp; 26.07.2011