如何在 Java 中反转 InputStream?

问题描述

假设我有一个输入流并且想要反转它!

我有类似的问题 How to get the content of an input stream in reverse order? 但首先那是大约 8 岁,而且这不是我想要的!

假设我有一个 InputStream 像:

FileInputStream in = new FileInputStream(new File("some_random_file.bin"));

注意这不是专门针对文本文件,而是针对二进制文件

现在

我有办法扭转它:

public static InputStream reverseStream(InputStream in) throws Exception{
    byte bytes[] = in.readAllBytes();
    byte bytesRev[] = new byte[bytes.length];
    for(int i=bytes.length - 1,j = 0;i >= 0; i--,j++)
        bytesRev[i] = bytes[j];
    return new ByteArrayInputStream(bytesRev);
}

但我不确定这是最有效的方法

即使对于大文件,我也想有一种有效的方法来实现这一点!

解决方法

如果您愿意将整个文件读入内存,那么您的解决方案非常好。可以通过反转已放置的内容而不是分配第二个数组来存储反转的内容来改善内存占用:

public static InputStream reverseStream(InputStream in) throws Exception{
    byte bytes[] = in.readAllBytes();
    for(int i=bytes.length - 1,j = 0;i >j; i--,j++) {
        byte tmp = bytes[i];
        bytes[i] = bytes[j];
        bytes[j] = tmp;
    }
    return new ByteArrayInputStream(bytes);
}

如果文件太大以至于您不想一次加载它,那么您将需要使用类 java.io.RandomAccessFile 以相反的顺序读取文件。您将需要使用某种内部缓冲来避免糟糕的性能。您可以将其封装在您自己的 InputStream 实现中,该实现通过缓冲区向后读取,根据需要动态加载新的缓冲区。

这是我对一个这样做的类的刺伤。这段代码完全未经测试(尽管它可以编译)。

/**
 * An input stream that reads a file in reverse. (UNTESTED)
 *
 * @author Ted Hopp
 */
class ReverseFileInputStream extends InputStream {
    private final RandomAccessFile file;
    /** Internal buffer for reading chunks of the file in reverse. */
    private final byte[] buffer;
    /** Position of the start of the buffer in the file. */
    private long bufferPosition;
    /** Position of the next byte to be read from the buffer. */
    private int bufferCursor;

    public ReverseFileInputStream(File file,int bufferSize) throws IOException {
        this.file = new RandomAccessFile(file,"r");
        buffer = new byte[bufferSize];
        bufferPosition = this.file.length();
        bufferCursor = -1;
    }

    @Override public int read() throws IOException {
        if (bufferCursor < 0) {
            fillBuffer();
        }
        return bufferCursor < 0 ? -1 : (buffer[bufferCursor--] & 0xff);
    }

    @Override public void close() throws IOException {
        file.close();
    }

    private void fillBuffer() throws IOException {
        if (bufferPosition > 0) {
            long newBufferPosition = Math.max(0L,bufferPosition - buffer.length);
            bufferCursor = (int) (bufferPosition - newBufferPosition);
            file.seek(newBufferPosition);
            file.readFully(buffer,bufferCursor--);
            bufferPosition = newBufferPosition;
        }
    }
}

请注意,如果您尝试将 Reader 包裹起来,结果很可能是无意义的,除非底层文件的文本编码是每个字符一个字节。同样与 DataInputStream