写入具有容量限制的 OutputStream

writing to OutputStream having capacity restriction

根据我之前询问的 :我正在实施具有容量限制的 ByteArrayOutputStream。我的主要限制是可用内存量。所以有这样的流 os:

  1. 当我向输出流写入更多 1MB 时,我需要 "stop"。 我宁愿不抛出异常,而是写 os 的完整内容 输出流到指定的其他输出流参数。 OutputStream out; os.writeTo(out); 然后继续写到os从头开始

  2. 为了防止出现1.描述的情况,我更倾向于drain os, 和 possible 一样频繁。我的意思是将数据从它复制到 out in chuncks 共 512KB 可行吗?如果是,有什么建议怎么办?或者可能有一个内置的 class 可以满足我的要求

编辑: 写入 out 的字节数也有限制。我最多可以在那里写1GB。如果我有更多,我需要创建其他输出流以便从 os 那里排出。 写入os的过程。可以是那样的。那里写了 500MB - 我立即将它转移到外面。几秒钟后,那里写入了 700MB - 我只需要将 500MB 排出到 out,将其他 200MB 排出到其他输出流(out2),我需要在这种情况下创建这些输出流

您所描述的是一个 BufferedOutputStream,您可以这样构造它:

new BufferedOutputStream(out, 512000)

第一个参数是您拥有的另一个输出流,第二个参数是 BufferedOutputStream 内部缓冲区的大小

编辑:

好的,一开始我没有完全理解你的需求。您确实需要扩展 OutputStream 才能实现这一目标。这是一个示例代码:

下面是如何使用下面的代码:

    public static void main(String[] args) throws IOException {
        AtomicLong idx = new AtomicLong(0);
        try (
            OutputStream out = new OutputStreamMultiVolume(10, () -> new FileOutputStream(getNextFilename(idx)));
            ) {

            out.write("01234567890123456789012345678901234567890123456789".getBytes("UTF-8"));
        }
    }

    private static File getNextFilename(AtomicLong idx) {
        return new File("sample.file." + idx.incrementAndGet() + ".txt");
    }

OutputStreamMultiVolume 的第一个构造函数 arg 是卷的最大大小。如果我们达到这个大小,我们将关闭当前的 outputStream,并调用 OutputStreamSupplier 获取下一个。

此处的示例代码会将字符串 01234567890123456789012345678901234567890123456789(0123456789 的 5 倍)写入名为 'sample.file.idx.txt' 的文件,其中每次达到外流最大大小时 idx 都会增加(因此您将得到 5文件)。

和 class 本身:

public class OutputStreamMultiVolume extends OutputStream {

    private final long maxBytePerVolume;
    private long bytesInCurrentVolume = 0;
    private OutputStream out;
    private OutputStreamSupplier outputStreamSupplier;

    static interface OutputStreamSupplier {
        OutputStream get() throws IOException;
    }

    public OutputStreamMultiVolume(long maxBytePerOutput, OutputStreamSupplier outputStreamSupplier) throws IOException {
        this.outputStreamSupplier = outputStreamSupplier;
        this.maxBytePerVolume = maxBytePerOutput;
        this.out = outputStreamSupplier.get();
    }

    @Override
    public synchronized void write(byte[] bytes) throws IOException {
        final int remainingBytesInVol = (int) (maxBytePerVolume - bytesInCurrentVolume);
        if (remainingBytesInVol >= bytes.length) {
            out.write(bytes);
            bytesInCurrentVolume += bytes.length;
            return;
        }

        out.write(bytes, 0, remainingBytesInVol);
        switchOutput();

        this.write(bytes, remainingBytesInVol, bytes.length - remainingBytesInVol);
    }

    @Override
    public synchronized void write(int b) throws IOException {
        if (bytesInCurrentVolume + 1 <= maxBytePerVolume) {
            out.write(b);
            bytesInCurrentVolume += 1;
            return;
        }

        switchOutput();
        out.write(b);
        bytesInCurrentVolume += 1;
    }

    @Override
    public synchronized void write(byte[] b, int off, int len) throws IOException {
        final int remainingBytesInVol = (int) (maxBytePerVolume - bytesInCurrentVolume);
        if (remainingBytesInVol >= len) {
            out.write(b, off, len);
            bytesInCurrentVolume += len;
            return;
        }

        out.write(b, off, remainingBytesInVol);
        switchOutput();
        this.write(b, off + remainingBytesInVol, len - remainingBytesInVol);
        bytesInCurrentVolume += len - remainingBytesInVol;
    }

    private void switchOutput() throws IOException {
        out.flush();
        out.close();

        out = outputStreamSupplier.get();
        bytesInCurrentVolume = 0;
    }

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

    @Override
    public synchronized void flush() throws IOException {
        out.flush();
    }
}

我想您可以尝试将 java.nio.ByteBuffer 与具有方法 newChannel(OutputStream);

java.nio.channel.Channels 结合使用

像这样:

ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
//... use buffer
OutputStream out = ...
drainBuffer(buffer, out);

public void drainBuffer(ByteBuffer buffer, OutputStream stream) {
   WritableByteChannel channel = Channels.newChannel(stream);
   channel.write(buffer);
}

恐怕您原来的 没有完全解释,所以您得到的答案也不是。

你不应该使用也不扩展BytArrayOutputStream来刷新,因为它的主要特点是“将数据写入字节数组”:即:所有数据都在内存中,所以您可以稍后通过 toByteArray.

检索它

如果你想刷新你超出的数据,你需要一个缓冲方法:这个结构就足够了:

OutputStream out=new FileOutputStream(...);
out=new BufferedOutputStream(out, 1024*1024);

为了定期刷新数据,您可以安排一个 TimerTask 来调用 flush:

Timer timer=new Timer(true);
TimerTask timerTask=new TimerTask(){
   public void run()
   {
        try
        {
            out.flush();
        }
        catch (IOException e)
        {
            ...
        }
};
timer.schedule(timerTask, delay, period);