XML文件读取乱码且报String index out of range: -1错误求助
问题分析与解决思路
核心问题定位
开头的ÿþ是UTF-16LE编码的字节顺序标记(BOM),本地编辑器会自动识别并隐藏BOM,但你的代码读取时未处理编码和BOM,导致BOM被当成普通字符保留在字符串开头,进而让indexOf("<FatturaElettronicaHeader>")返回-1(目标字符串前多了BOM字符,匹配失败),触发下标越界错误。
之前的几千个文件都是无BOM的UTF-8或系统默认编码格式,所以第一种方式能正常工作,但这个特殊文件是带BOM的UTF-16LE编码,导致所有未指定正确编码的读取方式失效。
具体解决步骤
1. 明确文件编码与BOM处理
该文件的编码是UTF-16LE,开头的ÿþ对应字节0xFF 0xFE(UTF-16LE的BOM标识),读取时需要:
- 指定UTF-16LE编码解析字节
- 跳过或移除开头的BOM字符(避免干扰后续字符串匹配)
2. 修复读取代码
以下是两种可行的修复方案:
方案一:基于Files.readAllBytes处理
直接读取字节后,跳过BOM再转换为UTF-16LE字符串:
private static String readFile(File file, Writer writerArg) throws IOException { byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath())); int offset = 0; // 检测并跳过UTF-16LE的BOM(前两个字节为0xFF 0xFE) if (bytes.length >= 2 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE) { offset = 2; } String data = new String(bytes, offset, bytes.length - offset, StandardCharsets.UTF_16LE); writerArg.write(data); return data; }
方案二:基于InputStreamReader指定编码并移除BOM
用UTF-16LE编码读取后,手动移除开头的BOM字符(UTF-16LE的BOM解析后是\uFEFF):
private static String readFile(File file, Writer writerArg) throws IOException { try (FileInputStream fis = new FileInputStream(file); BufferedReader br = new BufferedReader(new InputStreamReader(fis, StandardCharsets.UTF_16LE))) { String data = br.lines().collect(Collectors.joining("\n")); // 移除开头的BOM字符 if (data.startsWith("\uFEFF")) { data = data.substring(1); } writerArg.write(data); return data; } }
3. 通用优化(可选)
如果后续可能遇到其他带BOM的编码文件,可以添加通用BOM检测逻辑,自动匹配编码:
// 简单BOM检测逻辑 private static Charset detectCharset(byte[] bytes) { if (bytes.length >= 3 && bytes[0] == (byte)0xEF && bytes[1] == (byte)0xBB && bytes[2] == (byte)0xBF) { return StandardCharsets.UTF_8; } else if (bytes.length >= 2) { if (bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE) { return StandardCharsets.UTF_16LE; } else if (bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) { return StandardCharsets.UTF_16BE; } } // 默认返回系统编码,或根据XML声明中的encoding属性判断(更准确) return Charset.defaultCharset(); }
可以结合XML声明中的encoding属性进一步验证编码,确保读取准确性。
为什么之前的方式失效?
- 第一种方式
FileReader使用系统默认编码(通常是UTF-8)读取UTF-16LE文件,必然出现乱码 - 第二种方式中
isr.getEncoding()获取的是系统默认编码(而非文件实际编码),后续用错误编码读取,结果依然乱码 - 第三种方式
new String(bytes)同样依赖系统默认编码,无法解析UTF-16LE的字节流,导致BOM和内容都乱码
内容的提问来源于stack exchange,提问作者Scripta14
相关产品推荐
相关产品推荐

