使用Java 7 NIO从类路径中读取文件

16

我已经在Google上搜索了相当长的时间,但所有的结果都指向Java 7之前的NIO解决方案。我已经使用NIO stuff从文件系统上的特定位置读取文件,这比以前容易得多(Files.readAllBytes(path))。现在,我想读取一个打包在WAR中并位于类路径上的文件。我们目前使用类似以下代码的方式实现:

Input inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();

/* iterate through the input stream to get all the bytes (no way to reliably find the size of the 
 *     file behind the inputStream (see http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available()))
 */
int byteInt = -1;
try
{
    byteInt = inputStream.read();
    while (byteInt != -1)
    {
        byteStream.write(byteInt);
        byteInt = inputStream.read();
    }

    byteArray = byteStream.toByteArray();
    inputStream.close();
    return byteArray;
}
catch (IOException e)
{
    //...
}

虽然这个方法可以工作,但我希望能够使用Java 7中的NIO来更轻松/更好地完成这个任务。我猜我需要获取一个Path对象来表示类路径上的这个路径,但我不确定该怎么做。
如果这是一个非常容易的事情,我道歉。我只是无法弄清楚。感谢您的帮助。

1
你尝试过使用 YourClass.class.getResourceAsStream(filename); 吗? - Dan W
1
是时候更新最佳答案了吗? - shreyas
4个回答

30

这对我有效。

import java.nio.file.Files;
import java.nio.file.Paths;

// fileName: foo.txt which lives under src/main/resources
public String readFileFromClasspath(final String fileName) throws IOException, URISyntaxException {
    return new String(Files.readAllBytes(
                Paths.get(getClass().getClassLoader()
                        .getResource(fileName)
                        .toURI())));
}

1
如果你使用命令行执行这段代码,并且foo.txt位于src/main/resources下,那么它不会起作用,因为从jar:file调用toURI()会导致NullPointerException - macemers
你可以使用直接读取到 String 的实用方法,而不是字节数组: Files.readString(Paths.get(getClass().getClassLoader().getResource(fileName).toURI())); - Praytic

8

路径表示文件系统上的文件。它不能帮助从类路径读取资源。您需要找到一个帮助方法,从流中读取所有内容(比您目前的方式更有效),并将其写入字节数组的方法。Apache commons-io 或 Guava 可以帮助您实现这一点。例如,使用 Guava:

byte[] array = 
    ByteStreams.toByteArray(this.getClass().getClassLoader().getResourceAsStream(resourceName));

如果你不想为此添加Guava或commons-io依赖项,你可以始终阅读它们的源代码并将其复制到自己的帮助程序方法中。

这并不是异步的,而这正是NIO的主要目的之一。 - Paul Draper
流未关闭。 - Tilman Hausherr

3
据我所理解,您想要打开一个ReadableByteChannel来读取资源,以便使用NIO进行读取。这应该是一个不错的起点。
// Opens a resource from the current class' defining class loader
InputStream istream = getClass().getResourceAsStream("/filename.txt");

// Create a NIO ReadableByteChannel from the stream
ReadableByteChannel channel = java.nio.channels.Channels.newChannel(istream);

1
你应该查看 ClassLoader.getResource()。它返回代表资源的URL。如果它是本地文件系统,那么它将是一个 file:// URL。此时,您可以剥离方案等内容,然后您就有了文件名,可以随意处理。
但是,如果它不是一个 file:// 路径,那么您可以回退到普通的 InputStream。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接