Наличие взлома инструмента из-за спецификации в файле UTF-8 - очень обычная вещь в моем опыте.Я не знаю, почему там, где так много отрицательных голосов (но тогда это дает мне возможность попытаться набрать достаточное количество голосов, чтобы выиграть специальный знак SO;)
Более серьезно: спецификация UTF-8 необычно имеет такой смысл , но он полностью действителен (хотя и обескуражен) спецификациями.Теперь проблема в том, что многие люди не знают, что спецификация допустима в UTF-8, и поэтому пишут неработающие инструменты / API, которые неправильно обрабатывают эти файлы.
Теперь у вас могут быть две разные проблемы: вы можете захотеть обработать файл из Java или вам нужно использовать Java для программного создания / исправления файлов, которые нужны другим (неработающим) инструментам.
У меня был случай на одном консультационном концерте, где служба поддержкипродолжайте получать сообщения от пользователей, у которых были проблемы с каким-либо текстовым редактором, который мог бы испортить совершенно корректные файлы UTF-8, созданные Java.Поэтому мне пришлось обойти эту проблему, убедившись, что спецификация удаляется из каждого отдельного файла UTF-8, с которым мы имели дело.
Если вы хотите удалить спецификацию из файла, вы можете создать новый файл.и пропустить первые три байта.Например:
... $ file /tmp/src.txt
/tmp/src.txt: UTF-8 Unicode (with BOM) English text
... $ ls -l /tmp/src.txt
-rw-rw-r-- 1 tact tact 1733 2012-03-16 14:29 /tmp/src.txt
... $ hexdump -C /tmp/src.txt | head -n 1
00000000 ef bb bf 50 6f 6b 65 ...
Как видите, файл начинается с "ef bb bf", это (полностью допустимая) спецификация UTF-8.
Вот метод, который принимаетфайла и создает его копию, пропустив первые три байта:
public static void workAroundbrokenToolsAndAPIs(File sourceFile, File destFile) throws IOException {
if(!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
source.position(3);
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom( source, 0, source.size() - 3 );
}
finally {
if(source != null) {
source.close();
}
if(destination != null) {
destination.close();
}
}
}
Обратите внимание, что он «сырой»: обычно вам нужно сначала убедиться, что у вас есть спецификация, прежде чем вызывать эту или «Плохую»Думает, что может произойти "[TM].
Вы можете посмотреть свой файл потом:
... $ file /tmp/dst.txt
/tmp/dst.txt: UTF-8 Unicode English text
... $ ls -l /tmp/dst.txt
-rw-rw-r-- 1 tact tact 1730 2012-03-16 14:41 /tmp/dst.txt
... $ hexdump -C /tmp/dst.txt
00000000 50 6f 6b 65 ...
И спецификация исчезла ...
Теперь, если вы просто хотитечтобы прозрачно удалить спецификацию для вашего сломанного Java API, вы можете использовать pushbackInputStream , описанный здесь: почему org.apache.xerces.parsers.SAXParser не пропускает спецификацию в кодировке utf8 xml?1031 *
private static InputStream checkForUtf8BOMAndDiscardIfAny(InputStream inputStream) throws IOException {
PushbackInputStream pushbackInputStream = new PushbackInputStream(new BufferedInputStream(inputStream), 3);
byte[] bom = new byte[3];
if (pushbackInputStream.read(bom) != -1) {
if (!(bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF)) {
pushbackInputStream.unread(bom);
}
}
return pushbackInputStream; }
Обратите внимание, что это работает, но определенно НЕ исправит более серьезную проблему, в которой другие инструменты в рабочей цепочке могут работать некорректно с файлами UTF-8, имеющимиСпецификация.
А вот ссылка на вопрос с более полным ответом, включая и другие кодировки:
Порядок следования байтов портит чтение файлов в Java