如何使用FileInputStream访问jar包中的txt文件?

7

我知道getResourceAsStream()方法,但解析文件的解析器存在问题,整个结构都是实现为期望FileInputStream(),而getResourceAsStream()返回一个未经过类型转换的输入流。有没有什么简单的“修复”这种情况的方法?


1
这就是为什么编写代码时最好针对接口而不是实现的原因。 - Powerlord
不应将输入流强制转换为其实现。它们被设计用于实现管道和过滤器。也就是说,一个(文件)输入流从文件中读取,另一个解压缩(GZipI.S.),另一个断开行(bufferedI.S.),等等。因此,如果您的程序期望一系列字节流,请期望一个输入流(任何I.S.),然后提供其一些实现。如果要转换流,请将其连接在一起:例如,new GZipInputStream(new FileInputStream(path))。 - helios
3个回答

21

位于JAR文件中的资源本身不是文件,无法使用FileInputStream读取。如果您的代码绝对需要一个FileInputStream,那么您需要使用getResourceAsStream()提取数据,将其复制到临时文件中,然后将该临时文件的FileInputStream传递给您的代码。

当然,在未来,请不要编写指望具体实现(如InputStream)的代码,您肯定会后悔的。


5

我最近遇到了相同的问题。我们使用的第三方库从FileInputStream中读取资源,但这些资源可以在JAR文件或远程服务器上。以前我们将这些资源写入临时文件,但这样做会导致过多的开销。

更好的解决方案是编写一个包装InputStream的FileInputStream类。以下是我们使用的类:

public class VirtualFileInputStream extends FileInputStream {

    private InputStream stream;

    public VirtualFileInputStream(InputStream stream) {
        super(FileDescriptor.in); // This will never be used
        this.stream = stream;
    }




    public int available() throws IOException {
        throw new IllegalStateException("Unimplemented method called");
    }


    public void close() throws IOException {
        stream.close();
    }


    public boolean equals(Object obj) {
        return stream.equals(obj);
    }


    public FileChannel getChannel() {
        throw new IllegalStateException("Unimplemented method called");
    }


    public int hashCode() {
        return stream.hashCode();
    }


    public void mark(int readlimit) {
        stream.mark(readlimit);
    }


    public boolean markSupported() {
        return stream.markSupported();
    }


    public int read() throws IOException {
        return stream.read();
    }


    public int read(byte[] b, int off, int len) throws IOException {
        return stream.read(b, off, len);
    }


    public int read(byte[] b) throws IOException {
        return stream.read(b);
    }


    public void reset() throws IOException {
        stream.reset();
    }


    public long skip(long n) throws IOException {
        return stream.skip(n);
    }


    public String toString() {
        return stream.toString();
    }

}

1
+1 但我会称它为FakeFileInputStream以强调需要伪造事物的重要性 :) 并鼓励不使用具体的FileInputStream实现。 - helios

0

不要认为你的解析器只适用于FileInputStream而不是InputStream

如果真是这种情况,而你必须使用该解析器

有两个选择

  1. 使用适配器模式创建CustomFileInputStream并覆盖相应方法,更多地将getResourceAsStream数据重定向到CustomFileInputStream

  2. 将getResourceAsStream保存到临时文件中,然后解析临时文件,在完成后删除该文件


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