【问题标题】:Tokenize Java InputStream into streams, not Strings将 Java InputStream 标记为流,而不是字符串
【发布时间】:2013-07-07 19:45:49
【问题描述】:

我非常了解 Java 库,所以当我意识到显然没有简单的方法可以用流来完成看似简单的事情时,我感到很惊讶。我正在尝试读取包含多部分表单数据的 HTTP 请求(大的多行标记分隔为分隔符,例如,------WebKitFormBoundary5GlahTkFmhDfanAn--),并且我想读取直到遇到具有给定名称的请求的一部分,然后返回该部分的 InputStream。

我可以将流读入内存并返回ByteArrayInputStream,因为提交的文件不应大于 1MB。但是,我想确保如果文件大于 1MB,读取方法会引发异常,以便过大的文件不会填满 JVM 的内存并导致服务器崩溃。文件数据可能是二进制的,因此排除了BufferedReader.readLine()(它会删除换行符,可以是\r\n\r\n 中的任何一个,从而导致数据丢失)。

所有明显的标记化解决方案,例如Scanner,都将标记读取为Strings,而不是流,这可能会导致OutOfMemoryErrors 用于大文件——这正是我想要避免的。据我所知,没有与Scanner 等效的方法将每个令牌作为InputStream 返回而不将其读入内存。有什么我遗漏的东西,或者有什么方法可以自己创建类似的东西,只使用标准 Java 库(no Apache Commons 等),不需要我阅读一次流一个字符并自己编写所有令牌扫描代码?


附录:在发布此之前不久,我意识到解决我最初问题的明显方法是将完整的请求正文读入内存,如果它太大则失败,然后对结果进行标记ByteArrayInputStreamScanner。这是低效的,但它有效。但是,我仍然很想知道是否有办法将InputStream 标记为子流,无需将它们读入内存,无需使用额外的库,也无需进行逐个字符处理。

【问题讨论】:

    标签: java forms inputstream


    【解决方案1】:

    如果不将它们加载到内存中(您不想要的解决方案)或将它们保存到磁盘(I/O 变得繁重),这是不可能的。将流标记为单独的流而不将其加载到内存中意味着您可以读取流(对其进行标记)并能够稍后再次读取它。简而言之,您想要的是不可能的除非您的流是可搜索的,但这些通常是用于非常特定的应用程序和专用 I/O 对象的专用流,例如 RandomAccessFile

    【讨论】:

    • 如果严格按顺序读取令牌流,则无需在流中查找。理想的解决方案是按顺序一次提供一个流,每个流在到达下一个分隔符时结束,此时可以创建下一个流。
    • @ACE91 我开始输入那个,但认为它是多余的。我能想到的唯一原因是异步处理数据。
    猜你喜欢
    • 2016-10-22
    • 2017-08-15
    • 2011-11-15
    • 2012-12-16
    • 2018-11-05
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    相关资源
    最近更新 更多