【问题标题】:downloading xml, delete bom and encode utf8下载xml,删除bom并编码utf8
【发布时间】:2014-01-27 14:22:30
【问题描述】:

我正在从 FTP 服务器下载 XML。我必须为我的 SAX 解析器准备它。为此,我需要删除 BOM 字节并将其编码为 UTF-8。但不知何故,它不适用于每个文件。

这是我的两个函数的代码:

public static void copy(File src, File dest){

    try {
        byte[] data = Files.readAllBytes(src.toPath());

        writeAsUTF8(dest, skipBom(data));

    } catch (IOException e) {
        e.printStackTrace();
    }
}


private static void writeAsUTF8(File out, byte[] data){

    try {

        FileOutputStream outStream = new FileOutputStream(out);
        OutputStreamWriter outUTF = new OutputStreamWriter(outStream,"UTF8");

        outUTF.write(new String(data, "UTF8"));
        //outUTF.write(new String(data));
        outUTF.flush();
        outStream.close();
        outUTF.close();
    }
    catch(Exception ex){
        ex.printStackTrace();
    }
}

    private static byte[] skipBom(byte[] data){

    int skipBytes = getBomSize(data);

    byte[] tmp = new byte[data.length - skipBytes];

    for(int x = 0; x < tmp.length; x++){
        tmp[x] = data[x + skipBytes];
    }

    return tmp;
}

任何想法我做错了什么?

【问题讨论】:

标签: java xml utf-8


【解决方案1】:

简化。

    writeAsUTF8(dest, data);



try {
    int BOM_LENGTH = "\uFFFE".getBytes(StandardCharsets.UTF_8);
    if (!new String(data, 0, BOM_LENGTH).equals("\uFFFE")) {
        BOM_LENGTH = 0;
    }
    FileOutputStream outStream = new FileOutputStream(out);
    outStream.write(data, BOM_LENGTH, data.length - BOM_LENGTH));
    outStream.close();
}
catch(Exception ex){
    ex.printStackTrace();
}

这会检查 BOM (U+FFFE) 是否存在。仅将所有内容读取为 String 会更简单:

String xml = new String(data, StandardCharsets.UTF_8);
xml = xml.replaceFirst("^\uFFFE", "");

使用 Charset 而不是 String 编码参数意味着可以少捕获一个异常:UnsupportedEncodingException(一个 IOException)。


检测 XML 编码:

String xml = new String(data, StandardCharsets.ISO_8859_1);
String encoding = xml.replaceFirst(
        "(?s)^.*<\\?xml.*encoding=([\"'])([\\w-]+)\\1.*\\?>.*$",
        "$2");

if (encoding.equals(xml)) {
    encoding = "UTF-8";
}
xml = new String(data, encoding);
xml = xml.replaceFirst("^\uFFFE", "");

【讨论】:

  • BOM 不是问题,删除它总是有效的。主要问题是编码,我使用 .readAllBytes() 将其作为字节读取,然后尝试将其保存为 utf-8。源文件可以有任何编码,但最后它必须是 utf8。
  • 使用 XML 中声明的编码添加。
  • 这个 ""(?s)"^.*.* $", "$2");"不工作
  • 我更正了正则表达式:无关的",缺少反斜杠,在编码中忘记了-
【解决方案2】:

为什么要删除 BOM 字节?您只需要将文件读取为具有文件编码的字符串,然后将字符串写入使用 UTF-8 编码的文件。

【讨论】:

  • 我不会,但是在使用 sax 解析器读取它时出现异常(第 1 行的符号无效,或类似的东西)
  • 你向 sax 解析器提供什么?当您提供包含阅读器的输入源时(知道字节必须以 utf-8 格式读取),那么一切都应该没问题。还是我理解错了?
  • @faith:不,这并不总是有效。如果输入流中的第一个字节是 BOM,那么 SAX 将抱怨非法字节并抛出异常。在这种情况下,您需要在将数据交给 SAX 之前去掉第一个字节。
  • 我正在用文件喂他
  • 我会对实际代码和导致此类异常的文件非常感兴趣。
【解决方案3】:

我无法弄清楚您的代码有什么问题。前段时间我也遇到过同样的问题,我用下面的代码来做。首先,下面的函数读入一个跳过第一个字节的文件。这当然只有在您确定所有文件都有 BOM 时才有意义。

public byte[] load (File inputFile, int lines) throws Exception {

    try (BufferedReader reader
        = new BufferedReader(
            new InputStreamReader(
                new FileInputStream(inputFile), "UTF-8")))
    {
        // Discard the Byte Order Mark
        int firstByte = reader.read();

        String line = null;
        int lineCount = 0;

        StringBuilder builder = new StringBuilder();
        while( lineCount <= lines && (line = reader.readLine()) != null ) {
            lineCount += 1;
            builder.append(line + "\n");
        }
    }

    return builder.toString().getBytes();
}

您可以重写上面的函数以将数据写回 UTF-8 格式的另一个文件。我偶尔使用以下方法将磁盘上的文件从 ISO 转换为 UTF-8:

public static void convertToUTF8 (Path p) throws Exception {
    Path docPath = p;
    Path docPathUTF8 = docPath;

    InputStreamReader in = new InputStreamReader(new FileInputStream(docPath.toFile()), StandardCharsets.ISO_8859_1);

    CharBuffer cb = CharBuffer.allocate(100 * 1000 * 1000);
    int c = -1;

    while ( (c = in.read()) != -1 ) {
        cb.put((char) c);
    }
    in.close();

    OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(docPathUTF8.toFile()), StandardCharsets.UTF_8);

    char[] x = new char[cb.position()];
    System.arraycopy(cb.array(), 0, x, 0, x.length);

    out.write(x);
    out.flush();
    out.close();
}

【讨论】:

    猜你喜欢
    • 2013-07-15
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    相关资源
    最近更新 更多