Java如何从指定的字节位置读取文件的一部分?

7

我需要读取文件的一部分,从指定的字节位置开始。

我尝试了以下代码:

protected void writePartToStream(final InputStream in, final OutputStream out, long startBytes) {
        final byte[] b = new byte[BUFFER_SIZE];
        int count = 0;
        amountWritten = startBytes;


        // skip logic
        // how to skip???

        do {
            // write to the output stream
            try {


                out.write(b, 0, count);
                out.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }

            amountWritten += count;
            System.out.println("Amount writtent=" + amountWritten);
            // read more bytes from the input stream
            try {
                count = in.read(b, (int) amountWritten, b.length);
            } catch (IOException e) {
            }
        } while (count != -1 && !getStatus().equals(Status.cancelled));

        // the connection was likely terminated abrubtly if these are not equal
        if (!getStatus().equals(Status.cancelled) && getError() == Error.none
                && amountWritten != fileSize) {
            setStatus(Status.error);
            this.error = Error.connection;
        }
    }

但是我从未涉及I/O操作,因此不知道如何开始读取指定位置的文件。


1
FileInputStream类(https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html)有一个名为`read(byte[] b, int off, int len)`的方法,您可以在其中指定起始位置。 - callOfCode
4个回答

8

另一种方式是使用文件的通道直接从任意位置读取数值,如下例所示:

int amountBytesToRead = 1337;
int positionToRead = 4211;
FileInputStream fis = new FileInputStream("test.txt");

//A direct ByteBuffer should be slightly faster than a 'normal' one for IO-Operations
ByteBuffer bytes = ByteBuffer.allocateDirect(amountBytesToRead);
fis.getChannel().read(bytes, positionToRead);

byte[] readBytes = bytes.array();
//Handle Bytes

1
谢谢。但是当我使用allocateDirect方法时,我遇到了java.lang.UnsupportedOperationException异常,具体位置在java.nio.ByteBuffer.array处。当使用allocate方法时,它可以正常运行。 - Prabhakaran M

2

请看java.io.RandomAccessFile.seek()。它允许从任意位置读取文件,但其构造函数需要一个文件名或File对象,而不仅仅是您的方法当前接收到的输入流。


看起来这就是我要找的。我会试一下,如果有帮助的话 - 我会批准它。 - Sergey Shustikov

1
你可以使用 FileChannelFileChannel.position(long)方法来设置FileInputStream文件中的位置:
FileInputStream fis = ...
long offset = ...
fis.getChannel().position(offset);

// read data from fis

0

使用FileInputStream.getChannel().read(ByteBuffer, long position)代替

这个方法不会修改文件的当前位置

static class FileInputStreamNoModifyCurrentPosition extends InputStream {
    private long mCurrentPosition;
    private long mRemaining;
    private final FileInputStream mFileInputStream;

    public FileInputStreamNoModifyCurrentPosition(FileInputStream fileInputStream, long offset, long length) throws IOException {
        mFileInputStream = fileInputStream;
        mCurrentPosition = offset;
        mRemaining = length;
    }

    @Override
    public int available() throws IOException {
        return (int) mRemaining;
    }

    @Override
    public int read() throws IOException {
        byte[] buffer = new byte[1];
        if (read(buffer) > 0) {
            return (int) buffer[0] & 0xFF;
        } else {
            return -1;
        }
    }

    @Override
    public int read(byte[] buffer, int offset, int count) throws IOException {
        if (mRemaining >= 0) {
            int readCount = mFileInputStream.getChannel().read(ByteBuffer.wrap(buffer, offset, (int) Math.min(count, mRemaining)), mCurrentPosition);
            if (readCount > 0) {
                skip(readCount);
            }
            return readCount;
        }
        return -1;
    }

    @Override
    public int read(byte[] buffer) throws IOException {
        return read(buffer, 0, buffer.length);
    }

    @Override
    public long skip(long count) throws IOException {
        mCurrentPosition += count;
        mRemaining -= count;
        return count;
    }

    @Override
    public void mark(int readlimit) {
        super.mark(readlimit);
    }

    @Override
    public boolean markSupported() {
        return super.markSupported();
    }

    @Override
    public synchronized void reset() throws IOException {
        super.reset();
    }
}

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