【问题标题】:Reading XML file encoded in UTF16 in Java在 Java 中读取以 UTF16 编码的 XML 文件
【发布时间】:2015-06-18 14:37:39
【问题描述】:

我正在尝试使用 Java 读取 UTF-16 xml 文件。 该文件是用 C# 编写的。

这是java代码:

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLReadTest
{
    public static void main(String[] s)
    {
        try
        {
            File fXmlFile = new File("C:\\my_file.xml");

            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fXmlFile);

            doc.getDocumentElement().normalize();

            NodeList nList = doc.getElementsByTagName("row");

            for (int temp = 0; temp < nList.getLength(); temp++)
            {
                Node nNode = nList.item(temp);

                if (nNode.getNodeType() == Node.ELEMENT_NODE)
                {
                    Element eElement = (Element) nNode;

                    System.out.println("FILE_NAME: " + eElement.getElementsByTagName("FILE_NAME").item(0).getTextContent());
                }
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }
}

这是 xml 文件:

<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<docMetadata>
  <row>
    <FILE_NAME>Выписка_Винтовые насосы.pdf</FILE_NAME>
    <FILE_CAT>GENERAL</FILE_CAT>
  </row>
</docMetadata>

在 Eclipse 和“运行/调试”设置窗口中运行此代码时,在名为“Common”的最后一个选项卡中,选择的编码是 Default - Inherited (Cp1253),我得到的输出是错误的:

FILE_NAME: ???????_?????????? ??????.pdf

当同一选项卡中选择的编码为 UTF-8 时,输出正常:

文件名:Выписка_Винтовые насосы.pdf

我做错了什么?

如何在 Eclipse 项目设置中使用默认编码 (cp 1253) 获得正确的输出?

此代码在我不想更改虚拟机默认编码的服务器中运行。

我已经用 Java 7 和 Java 8 测试过这段代码

【问题讨论】:

  • 您确定字符串的内容不同,而不仅仅是控制台输出有问题吗?如果您的默认编码不能代表您尝试输出的字符,那么它将无法正常工作...
  • 不仅仅是控制台输出。调试器中的字符串值也显示为“?????????.pdf”。下面的 Remy Lebeau 和 user3141592 解释了为什么它在我的 Eclipse 中不起作用。但是,如果我们将 eclipse 放在一边,如何在 Windows Server 中使用 .exe 文件执行的程序中解决这个问题?我需要更改代码中的某些内容,还是 Windows 设置中的某些内容?
  • 老实说,我很惊讶它不起作用。您能否将示例文件放到网络上,以便我们验证编码是否正确?
  • 这是文件:drive.google.com/file/d/0B86OsnzLlycjQm5RTHBUbXMyUnM/… 使用 Notepad++ 打开文件显示“UCS-2 Big Endian” 在实际程序执行场景中,xml 是从 C# Web 服务生成为字符串的,如下所示: XElement doc = new XElement("docMetadata"); // 将数据添加到我的 xml,然后: XDocument xmlInUtf16 = new XDocument(new XDeclaration("1.0", "UTF-16", "yes"), doc); StringWriter sr = new StringWriter(); xmlInUtf16.Save(sr);字符串 xmlStr = sr.ToString(); return xmlStr 下面续...
  • 然后Java把这个String放到DocumentBuilder中进行解析。在 eclipse 调试器中,当我查看 xml 字符串时,文件名在俄语中看起来不错。但是当我从文档构建器中提取它的值时,它在 Eclipse 中显示为 ???????.pdf(使用 Cp1253 时)。在 Eclipse 中使用 UTF-8 时结果正常。当我的程序在生产中运行时出现错误。

标签: java xml utf-16


【解决方案1】:

问题与 XML 本身无关。 Java 字符串采用 UTF-16 编码,Document 将 XML 数据正确解码为 UTF-16 字符串。真正的问题是您将 Eclipse 设置为使用 cp1253(Windows-1253 希腊语,与 ISO-8859-7 希腊语略有不同)作为其控制台字符集,但您尝试输出的大多数 Unicode 字符(俄语) 根本不存在于该字符集中,因此它们被替换为?。这也解释了为什么当控制台字符集设置为 UTF-8 时输出是正确的,因为 UTF8UTF16 转换是无损的。

【讨论】:

  • 你是对的(与下面的 user3141592 解释相同)。这个问题出现在一个用 Eclipse 开发的 java 程序中,在生产环境中它是用 Windows Server 中的 .exe 文件执行的。在生产环境中文件名出来了?????????????.pdf。如果我们把 Eclipse 放在一边,如何在生产环境中解决这个问题?
  • 不幸的是,Windows 的控制台对 Unicode 的支持非常有限,使用 System.out 时您无能为力,除了这个:stackoverflow.com/a/15516722/65863
【解决方案2】:

尝试在输入流中显式设置编码:

Document doc = dBuilder.parse(new InputStreamReader(new FileInputStream(fXmlFile), "UTF-16"));

【讨论】:

    【解决方案3】:

    如何在 Eclipse 项目设置中使用默认编码 (cp 1253) 获得正确的输出?

    你不能。要查看正确的输出,控制台必须知道要显示的字符。

    此代码在我不想更改虚拟机默认编码的服务器中运行。

    您可以编写一个 UTF-8/16 日志文件,您可以在其中使用 cat 从另一个控制台或文本编辑器查看输出。

                if (nNode.getNodeType() == Node.ELEMENT_NODE)
                {
                    Element eElement = (Element) nNode;
                    String message = "FILE_NAME: " + eElement.getElementsByTagName("FILE_NAME").item(0).getTextContent();
                    System.out.println(message);
                    // output FILE_NAME to logfile.txt (quick and dirty)
                    OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File("logfile.txt")), "UTF-8");
                    writer.write(message);
                    writer.close();
                }
    

    我在运行配置中使用 ISO-8859-1 编码在 Eclipse 中运行此代码。

    Eclipse 输出:FILE_NAME: ???????_???????? ??????.pdf

    日志文件输出:FILE_NAME: Выписка_Винтовые насосы.pdf

    【讨论】:

    • ISO-8859-1 中也不存在有问题的俄语字符。如果不是 UTF-8/16,您必须改用 ISO-8859-5。
    • 是的,我选择 ISO-8859-1 是为了表明问题出在控制台中的输出而不是读取 xml 文件。
    • 你是对的。在上面的示例中(使用 Eclipse 设置以使用 Cp1253),Eclipse 控制台输出显示 ??????????.pdf 但 logfile.txt 以俄语显示文件名。这个问题出现在一个用 Eclipse 开发的 java 程序中,在生产环境中它是用 Windows Server 中的 .exe 文件执行的。在生产环境中文件名出来了?????????????.pdf。如果我们把 Eclipse 放在一边,如何在生产环境中解决这个问题?
    • 在 java 方面你无能为力。您必须在生产环境中设置控制台字符集。 linux 上的示例:LANG=en_GB.ISO-8859-1 给我 FILE_NAME: ???????_???????? ??????.pdf。将控制台设置为LANG=en_GB.UTF-8 会给我正确的输出:FILE_NAME: Выписка_Винтовые насосы.pdf
    【解决方案4】:

    我使用旧的 dom4j 库来解析 xml,这导致了问题。 使用 JVM 1.7 嵌入式库解决了这个问题:

    import java.io.File;
    import java.io.StringReader;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.InputSource;
    
    public XMLDoc()
        {
            try
            {
                File xmlFile = new File("C:\\my_file.xml");
                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                Document doc = dBuilder.parse(xmlFile);
                doc.getDocumentElement().normalize();
    
                NodeList nList = _doc.getElementsByTagName("row");
                for (int i = 0; i < nList.getLength(); i++)
                {
                    Node nNode = nList.item(i);
    
                    if (nNode.getNodeType() == Node.ELEMENT_NODE)
                    {
                        Element eElement = (Element) nNode;
                        Node itemNode = eElement.getElementsByTagName("FILE_NAME").item(0);
                        String text = itemNode != null ? itemNode.getTextContent() : "";
    
                        // russian text is fine here
                    }
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多