【问题标题】:Does reading a text file in Java have a maximum line length?在 Java 中读取文本文件是否有最大行长?
【发布时间】:2014-05-13 07:57:38
【问题描述】:

我正在读取一个我无法控制其格式的 XML 配置文件,我需要的数据位于最后一个元素中。不幸的是,该元素是一个 base64 编码的序列化 Java 类(是的,我知道),长度为 31200 个字符。

一些实验似乎表明,如果我只是将文件读入字符串并打印出来,Java XML/XPath 库不仅看不到此元素中的值(它们默默地将值设置为空白字符串)为了控制台,所有内容(甚至是 next 行上的结束元素)都会被打印出来,但不是这个元素。

最后,如果我手动进入文件并将行分成行,Java 可以看到该行,尽管这显然会破坏 XML 解析和反序列化。这也不实用,因为我想制作一个可以跨许多此类文件工作的工具。

Java 中是否有一些行长限制会阻止此工作?我可以通过第三方库解决它吗?

编辑:这是与 XML 相关的代码:

FileInputStream fstream = new FileInputStream("path/to/xml/file.xml");
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document d = db.parse(fstream);
String s = XPathFactory.newInstance().newXPath().compile("//el1").evaluate(d);

【问题讨论】:

  • 好吧,行限制是Integer.MAX_VALUE,因为这是.length() 的最大可能值,但在这种情况下它并没有真正的帮助。
  • 你用的是什么库?您如何阅读文件(DOM、SAX、STaX)?例如,JAXP 有 a number of properties 控制可以读取的某些 XML 结构的最大大小,这可能与您的情况相关。
  • 我使用的是 DOM,只是基本的 DocumentBuilder API。添加上面的代码。
  • 您是否检查过d 是否包含所需的值,或者至少包含名为<el1> 的元素?

标签: java xml file xpath


【解决方案1】:

要读取大型 xml 文件,您可以使用 SAX 解析器。 除了在 SAX 解析器中读取“字符”内的值之外,还应该使用“字符串缓冲区”而不是字符串来读取。 您可以查看 SAX 解析器 here

【讨论】:

    【解决方案2】:

    我想知道是否有可能在您读入 XML 时对其进行一些预处理。

    我一直在尝试是否可以将长元素分解为子元素列表。然后可以对其进行解析,并且可以将子元素重新构建为字符串。我的测试提出了这样一个事实,即我最初猜测的每个子元素 4500 个字符对于我的 XML 解析来说仍然有点高,所以我只是随意选择了 1000 个,它似乎可以应付。

    无论如何,这可能会有所帮助,但可能不会,但这是我想出的:

    private static final String ELEMENT_TO_BREAK_UP_OPEN = "<element>";
    private static final String ELEMENT_TO_BREAK_UP_CLOSE = "</element>";
    private static final String SUB_ELEMENT_OPEN = "<subelement>";
    private static final String SUB_ELEMENT_CLOSE = "</subelement>";
    private static final int SUB_ELEMENT_SIZE_LIMIT = 1000;
    
    public static void main(final String[] args) {
        try {
    
            /* The XML currently looks like this:
             * 
             * <root>
             * <element> ... Super long input with 30000+ characters ... </element>
             * </root>
             * 
             */
            final File file = new File("src\\main\\java\\longxml\\test.xml");
            final BufferedReader reader = new BufferedReader(new FileReader(file));
    
            final StringBuffer buffer = new StringBuffer();
            String line = reader.readLine();
            while( line != null ) {
                if( line.contains(ELEMENT_TO_BREAK_UP_OPEN) ) {
                    buffer.append(ELEMENT_TO_BREAK_UP_OPEN);
                    String substring = line.substring(ELEMENT_TO_BREAK_UP_OPEN.length(), (line.length() - ELEMENT_TO_BREAK_UP_CLOSE.length()) );
    
                    while( substring.length() > SUB_ELEMENT_SIZE_LIMIT ) {
                        buffer.append(SUB_ELEMENT_OPEN);
                        buffer.append( substring.substring(0, SUB_ELEMENT_SIZE_LIMIT) );
                        buffer.append(SUB_ELEMENT_CLOSE);
    
                        substring = substring.substring(SUB_ELEMENT_SIZE_LIMIT);
                    }
                    if( substring.length() > 0 ) {
                        buffer.append(SUB_ELEMENT_OPEN);
                        buffer.append(substring);
                        buffer.append(SUB_ELEMENT_CLOSE);
                    }
                    buffer.append(ELEMENT_TO_BREAK_UP_CLOSE);
                }
                else {
                    buffer.append(line);
                }
    
                line = reader.readLine();
            }
            reader.close();
    
    
            /* The XML now looks something like this:
             * 
             * <root>
             * <element>
             * <subElement> ... First Part of Data ... </subElement>
             * <subElement> ... Second Part of Data ... </subElement>
             * ... Multiple Other SubElements of Data ..
             * <subElement> ... Final Part of Data ... </subElement>
             * </element>
             * </root>
             */
    
            //This parses the xml with the new subElements in
            final InputSource src = new InputSource(new StringReader(buffer.toString()));
            final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getFirstChild();
    
            //This gives us the first child (element) then that's children (subelements)
            final NodeList childNodes = document.getFirstChild().getChildNodes();
    
            //Then concatenate them back into a big string.
            final StringBuilder finalElementValue = new StringBuilder();
            for( int i = 0; i < childNodes.getLength(); i++ ) {
                final Node node = childNodes.item(i);
                finalElementValue.append( node.getFirstChild().getNodeValue() );
            }
    
            //At this point do whatever you need to do. Decode, Deserialize, etc...
            System.out.println(finalElementValue.toString());
        }
        catch (final Exception e) {
            e.printStackTrace();
        }
    }
    

    在它的一般应用方面存在一些问题:

    • 它确实依赖于您要分解的元素是唯一可识别的。 (但我猜想找到元素的逻辑可以改进不少)
    • 它依赖于了解 XML 的格式并希望它不会改变。 (仅在后面的解析部分中,一旦将其分解为子元素,您可能会使用 xPath 更好地解析它)

    说了这么多,你最终得到了一个可解析的 XML 字符串,你可以从它构建你的编码字符串,所以这可能会帮助你找到解决方案。

    【讨论】:

    • @OlegEstekhin 这是一个非常公平的评论,通常我不会,但我建议在解析 XML 文件之前对它进行一些预处理,以使文件可解析通过通常的方法。我想知道如何在不手动读取文件的情况下进行这种预处理?
    猜你喜欢
    • 2011-12-04
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    相关资源
    最近更新 更多