【问题标题】:How to process a string with 823237 characters如何处理包含 823237 个字符的字符串
【发布时间】:2012-06-03 15:42:10
【问题描述】:

我有一个包含 823237 个字符的字符串。它实际上是一个 xml 文件,出于测试目的,我想作为响应形式返回一个 servlet。

我已经尝试了我能想到的一切

1) 用整个字符串创建一个常量...在这种情况下 Eclipse 抱怨(在 servlet 类名下有一条红线) -

 The type generates a string that requires more than 65535 bytes to encode in Utf8 format in the constant pool

2) 将整个字符串分成 20 个字符串常量并直接写入out 对象 类似:

out.println( CONSTANT_STRING_PART_1 + CONSTANT_STRING_PART_2 + 
             CONSTANT_STRING_PART_3 + CONSTANT_STRING_PART_4 +
             CONSTANT_STRING_PART_5 + CONSTANT_STRING_PART_6 + 
     // add all the string constants till .... CONSTANT_STRING_PART_20); 

在这种情况下……构建失败……抱怨……

   [javac] D:\xx\xxx\xxx.java:87: constant string too long
   [javac]      CONSTANT_STRING_PART_19 + CONSTANT_STRING_PART_20); 
                                                    ^

3) 将 xml 文件作为字符串读取并写入 out object .. 在这种情况下,我得到了

SEVERE: Allocate exception for servlet MyServlet
Caused by: org.apache.xmlbeans.XmlException: error: Content is not allowed in prolog.

最后我的问题是......我怎样才能从servlet 返回这么大的字符串(作为响应)???

【问题讨论】:

  • 我用 StringBuffer 做了,但构建再次失败,我得到与 2 one 相同的错误
  • 注意 String + String 创建一个新的 String ;-)
  • 在 XML 文档中的 prolog <?xml version="1.0"?> 之前不应有空行或空格或 xml 元素。

标签: java string servlets file-io io


【解决方案1】:

您可以避免使用流将所有文本加载到内存中:

    InputStream is = new FileInputStream("path/to/your/file"); //or the following line if the file is in the classpath
    InputStream is = MyServlet.class.getResourceAsStream("path/to/file/in/classpath");
    byte[] buff = new byte[4 * 1024];
    int read;  
    while ((read = is.read(buff)) != -1) {  
        out.write(buff, 0, read);  
    }

【讨论】:

    【解决方案2】:

    第二种方法可能通过以下方式起作用:

    out.print(CONSTANT_STRING_PART_1);
    out.print(CONSTANT_STRING_PART_2);
    out.print(CONSTANT_STRING_PART_3);
    out.print(CONSTANT_STRING_PART_4);
    // ...
    out.print(CONSTANT_STRING_PART_N);
    out.println();
    

    您当然可以循环执行此操作(强烈推荐 ;))。

    你这样做的方式,你只是暂时再次创建大字符串,然后将其传递给println(),这与第一个问题相同。

    【讨论】:

      【解决方案3】:

      Ropes: Theory and practice

      为什么以及何时使用 Ropes for Java 进行字符串操作

      【讨论】:

        【解决方案4】:

        您可以将 823K 文件读入字符串。也许不是最优雅的方法,但完全可行。方法3应该有效。有一个 XML 错误,但这与从文件读取到字符串或数据长度无关。

        不过,它必须是一个外部文件,因为它太大而无法内联到类文件中(这些文件有大小限制)。

        我推荐 Commons IO FileUtils#readFileToString

        【讨论】:

        • 但我将文件作为字符串读取对吗?那为什么xml错误?我不想在这个阶段解析它?只要调用 servlet .. 调用类就会在控制台中打印此异常!
        • 问题 3 是因为您的 xml 中有错误。 <? 之前可能有一些空白或一行。删除它们,它应该可以工作。
        【解决方案5】:

        您必须处理ByteArrayOutputStream 而不是自己的字符串。如果您想在 http 响应中发送您的字符串,您所要做的就是从该 byteArray 流中读取并写入响应流,如下所示:

        ByteArrayOutputStream baos = new ByteArrayOutputStream(8232237);
        baos.write(constant1.getBytes());
        baos.write(constant2.getBytes());
        ...
        baos.writeTo(response.getOutputStream());
        

        【讨论】:

        • 您能否提供更多详细信息...您是说我应该尝试将 char 数组写入 out 对象吗?
        • 好的,你创建一个 ByteArrayOutputStream 实例并在构造函数中声明它的大小为 823237。然后你使用 byteArrayStream.write(constant.getBytes()) 一个一个地写你的常量
        【解决方案6】:

        问题 1) 和 2) 都是由于相同的基本问题。字符串文字(或常量字符串表达式)不能超过 65535 个字符,因为类文件格式中的字符串常量有硬性限制。

        第三个问题听起来像是您实现它的方式中的一个错误,而不是一个基本问题。事实上,听起来您正在尝试将 XML 作为 DOM 加载,然后对其进行解析(这是不必要的),并且您设法在此过程中破坏了 XML。 (或者它可能在您尝试读取的文件中被破坏......)

        简单而优雅的解决方案是将内容保存在文件中,然后以纯文本形式读取。

        或者......不太优雅,但同样有效:

           String[] strings = new String[](
                "longString1",
                "longString2",
                ...
                "longStringN"};
        
           for (String str : strings) {
               out.write(str);
           }
        

        当然,将测试数据嵌​​入为字符串文字的问题在于,您必须对字符串中的某些字符进行转义以使编译器满意。如果您必须手动完成,那就太乏味了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-03-08
          • 2016-02-27
          • 1970-01-01
          • 2022-11-12
          • 1970-01-01
          • 2013-04-08
          • 2015-06-01
          相关资源
          最近更新 更多