Xerces UTF8Reader 中导致 MalformedByteSequenceException 的编码问题
Encoding Issue Causing MalformedByteSequenceException in Xerces UTF8Reader
我遇到 com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException
有一个 XML 文件。我使用调试器逐步执行 Xerces 代码,并缩小了发生这种情况的范围。我能够确定通过删除文档中的 "smart quote" 个字符,文档变得可解析。
文档没有 DTD。 Notepad++ 将其标记为 "ANSI as UTF-8"。 Firefox 将其标记为 "Western"。我记得在大学里听过一次不太惊心动魄的讲座,UTF-8 被设计为与单字节编码系统向后兼容。我还看到 on this chart,字节序列 e2 80 9d
实际上代表了 "RIGHT DOUBLE QUOTATION MARK",但即使我看不到编码问题,我认为存在一.
我从 Xerces 收到的异常消息是 Invalid byte 3 of 3-byte UTF-8 sequence.
它是从 UTF8Reader 的第 435 行的 invalidByte(3, 3, b2)
调用中抛出的。当我试图完全理解这种方法的逻辑时,我的大脑开始有点融化,所以我可能会遗漏一些东西,但正如我上面提到的字节 3 (0x90)。至少上面的序列,根据 UTF-8 table.
是有效的
这是十六进制编辑器中出现双引号的文件段:
我尝试了以下方法:
- 通过 Charset.forName("UTF-8")
使用 UTF-8 强制加载字符串
- 添加 DTD
<?xml version="1.0" encoding="UTF-8"?>
- 在 Notepad++ 中打开文件并通过 UI
将其编码为 UTF-8
- 上述的各种组合,有时会重复
指示为无效的字节似乎是 63(0x3F?)
我也试过将这个智能引号字符添加到以前可解析的文档中。正如预期的那样,它使解析器抛出相同的异常。
堆栈跟踪:
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:435)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
...
更新:
我仍然需要找到一种方法将其安全地转换为字符串。我使用 Notepad++ 将文件编码为 UTF-8。下面的代码成功地将字节加载到一个字符串中(我可以看到在 Eclipse 中调试时读取字符串中的 XML),但现在我得到了带有不同参数的 MalformedByteSequenceException。这次,我可以 post 代码和 XML 我正在使用:
File file = new File("ccd.xml");
byte[] ccdBytes = org.apache.commons.io.FileUtils.readFileToByteArray(file);
String ccdString = new String(ccdBytes, Charset.forName("UTF-8"));
CDAUtil.load(new ByteArrayInputStream(IOUtils.toByteArray(ccdString))); //method that's doing the parsing
堆栈跟踪:
Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:557)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
at org.openhealthtools.mdht.emf.runtime.resource.impl.FleXMLLoadImpl.load(FleXMLLoadImpl.java:55)
at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLResourceImpl.java:180)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1494)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:268)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:250)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:238)
然而,
CDAUtil.load(new FileInputStream(new File("ccd.xml")));
有效
您没有告诉我们您是如何将文件传递给 Xerces 的。你可以用不同的方式做不同的结果。您可以阅读有关 xml 编码问题的更详细解释
我建议您执行以下操作:
- 用记事本++打开文件,如果缺少
<?xml version="1.0"
encoding="UTF-8"?>
作为第一行
- 在 Notepad++ 中转换为 UTF-8(无 bom)(它应该在格式菜单中,但我使用的是意大利语版的 notepad++,所以我猜测菜单翻译)
- 保存文件
- 在 Java 中将其作为 InputStream 打开,即将 InputStream 和 NOT 作为 Reader 子类
传递给 xml 解析器
这应该可以解决问题,如果您可以通过将文件传递给解析器的代码,则更容易找到问题。
这些步骤解决了问题,因为 xml 中带有编码声明的第一行仅在您使用 InputStream(即字节流)时才会被解析器考虑。如果您读取字节流,则需要编码声明以指定如何将字节转换为字符。
如果您传递的是字符串,第一行是无用的,因为您传递的是字符流,不需要编码。
如果您想使用字符串,您必须将文件作为 InputStream 读取并转换为指定字符集的 Reader(类似于 InputStreamReader inputStreamReader= new InputStreamReader(xmlFileInputStream,"UTF-8");
)
我的猜测是您收到错误是因为您没有指定字符集并且 Java 选择了您的 os (Windows-1252) 之一。
只有当我的输入文件中存在实际的 UTF-8 编码错误时,我才能收到该错误消息。因此,我假设文件中某处存在您找不到的实际错误。
这是我的测试代码:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
public class ParseAXml {
public static void main(String argv[]) throws Exception {
String xmlFile = argv[0];
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlFile);
System.out.println("Parsed Successfully");
}
}
当我向它传递一个正确的文件 - 包含您所拥有的智能引号 - 我收到了预期的 Parsed Successfully
消息。这是我的常规测试文件:
$ hexdump -C tmp.xml
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 |<?xml version="1|
00000010 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54 |.0" encoding="UT|
00000020 46 2d 38 22 3f 3e 0a 3c 74 68 69 6e 67 3e 3c 61 |F-8"?>.<thing><a|
00000030 3e 54 68 69 73 20 e2 80 9c 71 75 6f 74 65 e2 80 |>This ...quote..|
00000040 9d 20 63 6f 75 6c 64 20 67 65 74 20 74 72 69 63 |. could get tric|
00000050 6b 79 3c 2f 61 3e 3c 2f 74 68 69 6e 67 3e 0a |ky</a></thing>.|
0000005f
当我测试一个有错误的文件时 - 通过修改偏移量 0x38 处的字节 - 我得到了你看到的异常:
$ java ParseAXml tmp.err.xml
Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:435)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2807)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:177)
at ParseAXml.main(ParseAXml.java:10)
所以为了帮助你,我写了一个简短的 java 程序试图找到格式错误的字节:
import java.nio.*;
import java.nio.charset.*;
import java.io.*;
public class FindBadUTF8 {
public static void main(String argv[]) throws Exception {
String filename = argv[0];
InputStream inStream = new FileInputStream(filename);
CharsetDecoder d=Charset.forName("UTF-8").newDecoder();
CharBuffer out = CharBuffer.allocate(1);
ByteBuffer in = ByteBuffer.allocate(10);
in.clear();
long offset = 0L;
while (true) {
int read = inStream.read();
if (read != -1) {
in.put((byte)read);
}
out.clear();
in.flip();
CoderResult cr = d.decode(in, out, (read == -1));
if (cr.isError()) {
if (read != -1) {
System.out.println("Error at offset " + offset + ": " + cr);
return;
} else {
System.out.println("Error at end-of-file: " + cr);
return;
}
}
if (cr.isUnderflow()) {
in.position(in.limit());
in.limit(in.capacity());
} else {
in.clear();
}
if (read == -1) {
break;
}
offset += 1L;
}
System.out.println("OK");
}
}
那个程序,当 运行 对我的示例文件有错误时,它给我这个:
$ java FindBadUTF8 tmp.err.xml
Error at offset 56: MALFORMED[2]
事实上,偏移量 56(十六进制为 0x38)是我损坏的字节:
$ hexdump -C tmp.err.xml
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 |<?xml version="1|
00000010 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54 |.0" encoding="UT|
00000020 46 2d 38 22 3f 3e 0a 3c 74 68 69 6e 67 3e 3c 61 |F-8"?>.<thing><a|
00000030 3e 54 68 69 73 20 e2 80 ff 71 75 6f 74 65 e2 80 |>This ...quote..|
00000040 9d 20 63 6f 75 6c 64 20 67 65 74 20 74 72 69 63 |. could get tric|
00000050 6b 79 3c 2f 61 3e 3c 2f 74 68 69 6e 67 3e 0a |ky</a></thing>.|
0000005f
我遇到 com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException
有一个 XML 文件。我使用调试器逐步执行 Xerces 代码,并缩小了发生这种情况的范围。我能够确定通过删除文档中的 "smart quote" 个字符,文档变得可解析。
文档没有 DTD。 Notepad++ 将其标记为 "ANSI as UTF-8"。 Firefox 将其标记为 "Western"。我记得在大学里听过一次不太惊心动魄的讲座,UTF-8 被设计为与单字节编码系统向后兼容。我还看到 on this chart,字节序列 e2 80 9d
实际上代表了 "RIGHT DOUBLE QUOTATION MARK",但即使我看不到编码问题,我认为存在一.
我从 Xerces 收到的异常消息是 Invalid byte 3 of 3-byte UTF-8 sequence.
它是从 UTF8Reader 的第 435 行的 invalidByte(3, 3, b2)
调用中抛出的。当我试图完全理解这种方法的逻辑时,我的大脑开始有点融化,所以我可能会遗漏一些东西,但正如我上面提到的字节 3 (0x90)。至少上面的序列,根据 UTF-8 table.
这是十六进制编辑器中出现双引号的文件段:
我尝试了以下方法:
- 通过 Charset.forName("UTF-8") 使用 UTF-8 强制加载字符串
- 添加 DTD
<?xml version="1.0" encoding="UTF-8"?>
- 在 Notepad++ 中打开文件并通过 UI 将其编码为 UTF-8
- 上述的各种组合,有时会重复
指示为无效的字节似乎是 63(0x3F?)
我也试过将这个智能引号字符添加到以前可解析的文档中。正如预期的那样,它使解析器抛出相同的异常。
堆栈跟踪:
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:435)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
...
更新: 我仍然需要找到一种方法将其安全地转换为字符串。我使用 Notepad++ 将文件编码为 UTF-8。下面的代码成功地将字节加载到一个字符串中(我可以看到在 Eclipse 中调试时读取字符串中的 XML),但现在我得到了带有不同参数的 MalformedByteSequenceException。这次,我可以 post 代码和 XML 我正在使用:
File file = new File("ccd.xml");
byte[] ccdBytes = org.apache.commons.io.FileUtils.readFileToByteArray(file);
String ccdString = new String(ccdBytes, Charset.forName("UTF-8"));
CDAUtil.load(new ByteArrayInputStream(IOUtils.toByteArray(ccdString))); //method that's doing the parsing
堆栈跟踪:
Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:557)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2815)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121)
at org.openhealthtools.mdht.emf.runtime.resource.impl.FleXMLLoadImpl.load(FleXMLLoadImpl.java:55)
at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLResourceImpl.java:180)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1494)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:268)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:250)
at org.openhealthtools.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:238)
然而,
CDAUtil.load(new FileInputStream(new File("ccd.xml")));
有效
您没有告诉我们您是如何将文件传递给 Xerces 的。你可以用不同的方式做不同的结果。您可以阅读有关 xml 编码问题的更详细解释
我建议您执行以下操作:
- 用记事本++打开文件,如果缺少
<?xml version="1.0" encoding="UTF-8"?>
作为第一行 - 在 Notepad++ 中转换为 UTF-8(无 bom)(它应该在格式菜单中,但我使用的是意大利语版的 notepad++,所以我猜测菜单翻译)
- 保存文件
- 在 Java 中将其作为 InputStream 打开,即将 InputStream 和 NOT 作为 Reader 子类 传递给 xml 解析器
这应该可以解决问题,如果您可以通过将文件传递给解析器的代码,则更容易找到问题。
这些步骤解决了问题,因为 xml 中带有编码声明的第一行仅在您使用 InputStream(即字节流)时才会被解析器考虑。如果您读取字节流,则需要编码声明以指定如何将字节转换为字符。
如果您传递的是字符串,第一行是无用的,因为您传递的是字符流,不需要编码。
如果您想使用字符串,您必须将文件作为 InputStream 读取并转换为指定字符集的 Reader(类似于 InputStreamReader inputStreamReader= new InputStreamReader(xmlFileInputStream,"UTF-8");
)
我的猜测是您收到错误是因为您没有指定字符集并且 Java 选择了您的 os (Windows-1252) 之一。
只有当我的输入文件中存在实际的 UTF-8 编码错误时,我才能收到该错误消息。因此,我假设文件中某处存在您找不到的实际错误。
这是我的测试代码:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
public class ParseAXml {
public static void main(String argv[]) throws Exception {
String xmlFile = argv[0];
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlFile);
System.out.println("Parsed Successfully");
}
}
当我向它传递一个正确的文件 - 包含您所拥有的智能引号 - 我收到了预期的 Parsed Successfully
消息。这是我的常规测试文件:
$ hexdump -C tmp.xml
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 |<?xml version="1|
00000010 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54 |.0" encoding="UT|
00000020 46 2d 38 22 3f 3e 0a 3c 74 68 69 6e 67 3e 3c 61 |F-8"?>.<thing><a|
00000030 3e 54 68 69 73 20 e2 80 9c 71 75 6f 74 65 e2 80 |>This ...quote..|
00000040 9d 20 63 6f 75 6c 64 20 67 65 74 20 74 72 69 63 |. could get tric|
00000050 6b 79 3c 2f 61 3e 3c 2f 74 68 69 6e 67 3e 0a |ky</a></thing>.|
0000005f
当我测试一个有错误的文件时 - 通过修改偏移量 0x38 处的字节 - 我得到了你看到的异常:
$ java ParseAXml tmp.err.xml
Exception in thread "main" com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 3 of 3-byte UTF-8 sequence.
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:687)
at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:435)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1753)
at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.skipChar(XMLEntityScanner.java:1426)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2807)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:347)
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:177)
at ParseAXml.main(ParseAXml.java:10)
所以为了帮助你,我写了一个简短的 java 程序试图找到格式错误的字节:
import java.nio.*;
import java.nio.charset.*;
import java.io.*;
public class FindBadUTF8 {
public static void main(String argv[]) throws Exception {
String filename = argv[0];
InputStream inStream = new FileInputStream(filename);
CharsetDecoder d=Charset.forName("UTF-8").newDecoder();
CharBuffer out = CharBuffer.allocate(1);
ByteBuffer in = ByteBuffer.allocate(10);
in.clear();
long offset = 0L;
while (true) {
int read = inStream.read();
if (read != -1) {
in.put((byte)read);
}
out.clear();
in.flip();
CoderResult cr = d.decode(in, out, (read == -1));
if (cr.isError()) {
if (read != -1) {
System.out.println("Error at offset " + offset + ": " + cr);
return;
} else {
System.out.println("Error at end-of-file: " + cr);
return;
}
}
if (cr.isUnderflow()) {
in.position(in.limit());
in.limit(in.capacity());
} else {
in.clear();
}
if (read == -1) {
break;
}
offset += 1L;
}
System.out.println("OK");
}
}
那个程序,当 运行 对我的示例文件有错误时,它给我这个:
$ java FindBadUTF8 tmp.err.xml
Error at offset 56: MALFORMED[2]
事实上,偏移量 56(十六进制为 0x38)是我损坏的字节:
$ hexdump -C tmp.err.xml
00000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 |<?xml version="1|
00000010 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54 |.0" encoding="UT|
00000020 46 2d 38 22 3f 3e 0a 3c 74 68 69 6e 67 3e 3c 61 |F-8"?>.<thing><a|
00000030 3e 54 68 69 73 20 e2 80 ff 71 75 6f 74 65 e2 80 |>This ...quote..|
00000040 9d 20 63 6f 75 6c 64 20 67 65 74 20 74 72 69 63 |. could get tric|
00000050 6b 79 3c 2f 61 3e 3c 2f 74 68 69 6e 67 3e 0a |ky</a></thing>.|
0000005f