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

У меня есть процесс 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 "tail -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 : 44: 06,100007. Строки были пропущены из этого второго сообщения XML. Дополнительные выводы: путь к файлу, с которого мы читаем файлы, находится на общем NAS.

Ответы [ 2 ]

7 голосов
/ 06 сентября 2012

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

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

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

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

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

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

0 голосов
/ 25 июля 2011

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

  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, должен быть неизвестен виртуальной машине.

...