InputStream 不从 JAR 中读取某些文件
InputStream does not read some files from a JAR
我已经为我的 Javalin 应用程序构建了一个 JAR 文件,代码运行得很好。然而,从 JAR 中读取一些资源文件失败并显示 inputStream.available() == 0
,但它对其他一些文件正好适用。
以下文件应该恰到好处地传送:
a/
|\
| +- a.txt
| +- b.js
| +- c.css
|
b/
\
+- d.png
+- e.txt
但是,InputStream
只读取文件 a/a.txt
、a/b.js
和 b/e.txt
。对于所有其他文件,它 returns 什么都没有,available() == 0
,但是当我不是从 JAR 中读取文件而是从提取的类路径中读取文件时它有效(并且我使用的是 ClassLoader
不管执行环境是什么样的)。此外,文件大小无关紧要,a/a.txt
比 a/c.css
大得多,所以我对此毫无头绪。
一些示例代码(如我所说,我使用 Javalin 作为 HTTP request/response,它在 ctx
对象,我还使用 Apache Tika 来检测所请求文件的 MIME 类型,这按预期工作):
// 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);
}
我是不是遗漏了什么,还是做错了什么?
我怀疑 MIME 类型检测可能是原因。首先,尝试将其排除在外,看看能否解决您的问题。
这是我的怀疑:tika.detect()
显然需要消耗给定流中的字节才能检测到任何内容。 classLoader.getResourceAsStream()
返回的InputStream
的method javadocs state that it can only reset the stream if it supports marking. Thus, you should verify that the markSupported()
method实际上是returnstrue
.
如果没有,Tika 可能会,例如消耗文件的所有内容,直到它可以确定文件类型,然后无法重置流,然后就没有任何东西可以发送给客户端了。在这种情况下,您应该将原始 InputStream
包装在 BufferedInputStream
中(添加 mark/reset 功能)并将其用于 tika 和发送内容。
顺便说一下:你真的应该使用 try with resources 来确保所有输入流、流 reader 和缓冲 reader 都关闭,即使在抛出异常时也是如此。
我已经为我的 Javalin 应用程序构建了一个 JAR 文件,代码运行得很好。然而,从 JAR 中读取一些资源文件失败并显示 inputStream.available() == 0
,但它对其他一些文件正好适用。
以下文件应该恰到好处地传送:
a/
|\
| +- a.txt
| +- b.js
| +- c.css
|
b/
\
+- d.png
+- e.txt
但是,InputStream
只读取文件 a/a.txt
、a/b.js
和 b/e.txt
。对于所有其他文件,它 returns 什么都没有,available() == 0
,但是当我不是从 JAR 中读取文件而是从提取的类路径中读取文件时它有效(并且我使用的是 ClassLoader
不管执行环境是什么样的)。此外,文件大小无关紧要,a/a.txt
比 a/c.css
大得多,所以我对此毫无头绪。
一些示例代码(如我所说,我使用 Javalin 作为 HTTP request/response,它在 ctx
对象,我还使用 Apache Tika 来检测所请求文件的 MIME 类型,这按预期工作):
// 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);
}
我是不是遗漏了什么,还是做错了什么?
我怀疑 MIME 类型检测可能是原因。首先,尝试将其排除在外,看看能否解决您的问题。
这是我的怀疑:tika.detect()
显然需要消耗给定流中的字节才能检测到任何内容。 classLoader.getResourceAsStream()
返回的InputStream
的method javadocs state that it can only reset the stream if it supports marking. Thus, you should verify that the markSupported()
method实际上是returnstrue
.
如果没有,Tika 可能会,例如消耗文件的所有内容,直到它可以确定文件类型,然后无法重置流,然后就没有任何东西可以发送给客户端了。在这种情况下,您应该将原始 InputStream
包装在 BufferedInputStream
中(添加 mark/reset 功能)并将其用于 tika 和发送内容。
顺便说一下:你真的应该使用 try with resources 来确保所有输入流、流 reader 和缓冲 reader 都关闭,即使在抛出异常时也是如此。