UTF-8ファイルからBOMを削除し、残りのxmlファイルのコピーを作成する方法についての提案が必要です。
UTF-8ファイルのBOMが原因でツールが壊れることは、私の経験ではveryよくあることです。なぜそこに多くの反対票があるのかわかりません(しかし、特別なSOバッジ;)を獲得するのに十分な票を獲得する機会を私に与えます。
もっと真剣に:UTF-8 BOMは通常それほど意味がありませんが仕様により完全に有効です(ただし、推奨されません)。問題は、BOMがUTF-8で有効であることを多くの人が認識していないため、これらのファイルを正しく処理しない壊れたツール/ APIを作成したことです。
ここで、2つの異なる問題が発生する可能性があります。Javaからファイルを処理するか、またはJavaを使用して、他のファイルをプログラムで作成/修正する必要があります(壊れた)ツールが必要です。
私はあるコンサルティングギグで、Javaによって生成された完全に有効なUTF-8ファイルを台無しにするテキストエディターで問題が発生したユーザーからのメッセージをヘルプデスクが受け取り続けるケースがありました。したがって、私が扱っていたすべてのUTF-8ファイルからBOMを必ず削除することで、この問題を回避する必要がありました。
ファイルからBOMを削除したい場合、新しいファイルを作成して最初の3バイトをスキップできます。例えば:
... $ 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 BOMです。
ファイルを受け取り、最初の3バイトをスキップしてそのコピーを作成するメソッドを次に示します。
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();
}
}
}
これは「未加工」であることに注意してください。通常、これを呼び出す前に、まずBOMがあることを確認するか、「悪い考えが起こる」[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 ...
そして、BOMはなくなりました...
ここで、壊れたJava APIのBOMを透過的に削除したい場合は、ここで説明されているpushbackInputStreamを使用できます。 なぜorg.Apache.xerces.parsers.SAXParserはutf8エンコードされたxmlでBOMをスキップしないのですか?
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; }
これは機能しますが、間違いなく[〜#〜] [〜#〜]は、他のツールをBOMのあるUTF-8ファイルでワークチェーンが正しく機能しない。
そして、他のエンコーディングもカバーする、より完全な答えのある質問へのリンクがあります: