【问题标题】:InputStream does not read some files from a JARInputStream 不从 JAR 中读取某些文件
【发布时间】:2018-12-14 04:31:42
【问题描述】:

我为我的Javalin 应用程序构建了一个JAR 文件,代码运行良好。但是,从 JAR 中读取一些资源文件会失败并显示 inputStream.available() == 0,但它对其他一些文件也能正常工作。

以下文件应该是正确的:

a/
|\
| +- a.txt
| +- b.js
| +- c.css
|
b/
 \
  +- d.png
  +- e.txt

但是,InputStream 仅读取文件a/a.txta/b.jsb/e.txt。对于所有其他文件,它什么都不返回,@ 987654331@,但是当我不是从 JAR 中读取文件而是从提取的 Classpath 中读取文件时它可以工作(并且无论执行环境看起来如何,我都在使用 ClassLoader喜欢)。另外,文件大小无关紧要,a/a.txta/c.css 大得多,所以我没有这方面的线索。

一些示例代码(正如我所说,我使用Javalin 处理HTTP 请求/响应,它在ctx 对象中处理,我还使用Apache Tika 来检测MIME-Type请求的文件,按预期工作):

// Example, real path is (correctly) fetched from the Context (ctx) object
String path = "a/c.css";

ClassLoader classLoader = Thread.currentThread ().getContextClassLoader ();
InputStream inputStream = classLoader.getResourceAsStream (path);

String contentType = tika.detect (inputStream, path);
ctx.header ("Content-Type", contentType);

if (contentType.contains ("text") || contentType.contains ("script")) {
    InputStreamReader streamReader = new InputStreamReader (inputStream);
    BufferedReader reader = new BufferedReader (streamReader);

    String line;
    StringBuilder builder = new StringBuilder ();
    while ((line = reader.readLine ()) != null) {
        builder.append (line).append ("\n");
    }

    String result = builder.toString ();
    ctx.header ("Content-Length", String.valueOf (result.length ()));
    ctx.result (result);

    reader.close ();
} else {
    ctx.header ("Content-Length", String.valueOf (inputStream.available ()));
    ctx.result (inputStream);
}

我在这里遗漏了什么还是我做错了什么?

【问题讨论】:

  • available() 不会做你认为它做的事情。事实上,你可以说它没有用。所以,如果你使用它,你做错了什么,它不会工作。尽量不要使用它,并用其他东西代替你认为你正在用它做的任何事情。那会奏效的。
  • 但是,HTTP 客户端没有收到任何内容。事实上,所有具有available() == 0 的文件的响应在从 JAR 中读取时都是 0 字节长。无论如何,当我从中删除 available() 的所有用法时,我的代码仍然无法从 JAR 中运行(让 Jetty 计算 Content-Length)...
  • 显然tika.detect() 正在消耗输入流中的字节:在某些情况下,所有字节。
  • @EJP 我敢打赌,文本文件会检测到这一点。 InputStream 提供了 mark(),它很可能适用于所有 Java 实现的 jar 资源,而 Tika 最有可能使用它。
  • @AlexanderLeithner 对具有 available() == 0 的文件的响应是空的,因为您声明它们的长度为零字节。当你不使用 available() 时,你能展示你的代码是什么样的吗?“不起作用”到底是什么意思?你的代码真的不应该去翻转汉堡。它只是假设在给定一些输入的情况下产生一些输出。

标签: java jar inputstream javalin


【解决方案1】:

我怀疑 MIME 类型检测可能是原因。首先,尝试将其排除在外,看看是否能解决您的问题。

这是我的怀疑:tika.detect() 显然需要消耗给定流中的字节才能检测到任何东西。 method javadocs 表示只有在支持标记的情况下才能重置流。因此,您应该验证由classLoader.getResourceAsStream() 返回的InputStream 中的markSupported() method 是否实际返回true

如果没有,Tika 可能会例如消耗文件的所有内容,直到它可以确定文件类型,然后无法重置流,然后没有任何东西可以发送给客户端。在这种情况下,您应该将原始 InputStream 包装在 BufferedInputStream(添加标记/重置功能)中,并将其用于 tika 和发送内容。


顺便说一句:你真的应该使用try with resources 来确保所有输入流、流读取器和缓冲读取器都关闭,即使抛出异常也是如此。

【讨论】:

  • 我知道我的代码缺少异常处理,我目前只是在寻找解决这个问题的方法。无论如何,谢谢!
猜你喜欢
  • 2013-02-20
  • 1970-01-01
  • 2015-07-25
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 2022-12-16
  • 2012-03-03
相关资源
最近更新 更多