Java регулярное выражение для байтов в потоке - PullRequest
3 голосов
/ 04 мая 2011

У меня есть XML-файлы (закодированные в UTF-8), которые имеют две проблемы:

  • Некоторые из них (не все) содержат знак порядка байтов EFBB BF

  • Некоторые из них (не все) содержат нулевые символы 00, распределенные по всему файлу.

Обе проблемы не позволяют мне выполнить синтаксический анализXML с парсером SAX.Мой текущий подход состоял в том, чтобы прочитать файл в строку и использовать регулярное выражение для извлечения этих символов и записи строки обратно в файл, который работал нормально.Однако мои файлы довольно велики (сотни мегабайт), и чтение файла в строку, создающее строку результата одинакового размера каждый раз, когда я вызываю replaceAll (), быстро приводит к ошибке пространства кучи Java.

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

Какие-либо предложения о том, как должно выглядеть эффективное решение?

Ответы [ 3 ]

7 голосов
/ 04 мая 2011

Я бы выделил подкласс FilterInputStream для фильтрации нежелательных байтов во время выполнения.

Задача должна быть довольно простой, поскольку метки порядка следования байтов, вероятно, находятся только в начале файла (поэтому вам нужно только проверитьтам) и nul-bytes можно легко изменить с помощью простого == сравнения (нет необходимости в регулярных выражениях).

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

1 голос
/ 04 мая 2011

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


Вы можете прочитать первые три байта с InputStream, который поддерживает mark() и reset(), прочитать первые три байта и сбросить, если они не были спецификацией:

InputStream in = new BufferedInputStream(
        new FileInputStream(new File("xmlfile.xml")));
in.mark(3);
byte[] maybeBom = new byte[] {
        (byte) in.read(), (byte) in.read(), (byte) in.read() };

if(!Arrays.equals(maybeBom, new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF })) {
    in.reset();
}

Я использую BufferedInputStream, потому что FileInputStream не поддерживает mark().

1 голос
/ 04 мая 2011

Почему бы вам не отфильтровать данные, когда вы читаете их в SAX-парсер. Таким образом, вам не нужно будет переписывать файл. Вы можете переопределить методы read () класса FilterInputStream, чтобы удалить ненужные байты.

Я думаю, именно это и предлагает @Joachim. ;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...