You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 07:36:20