【问题标题】:writing to OutputStream having capacity restriction写入具有容量限制的 OutputStream
【发布时间】:2015-10-08 14:42:10
【问题描述】:

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

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

  2. 为了防止1.中描述的情况,我宁愿排os, 尽可能频繁。我的意思是将数据从它复制到 out 块 512KB 可行吗?如果是的话,有什么建议怎么做?或者可能有一个内置类可以满足我的要求

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

【问题讨论】:

  • 您可能会发现 BufferedOutputStream 的默认缓冲区大小 8 KB 执行得很好,但增加缓冲区大小实际上会损害性能,因为它对缓存不友好。
  • @Peter Lawrey AFAIK,最佳缓冲区大小应该是 4 Kb(大多数架构上的典型页面大小)的倍数,以便将完整页面读/写到磁盘中。为什么更大的尺寸会损害性能?提前谢谢你。
  • 这里的实际要求是什么?在我看来,这听起来像是一种非常复杂的重新实现 BufferedOutoutStream 的方法。
  • @LittleSanti 当您有较大的缓冲区时,您将在较慢的缓存之间复制数据。通过测试,我认为 32 KB 在某些情况下是最快的,尽管并不比默认的 8 KB 快多少。对于我测试过的情况,1 MB 通常比较慢。
  • @EJP 看文档不清楚怎么用

标签: java outputstream capacity


【解决方案1】:

您所描述的是一个 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(5 次 0123456789)写入名为“sample.file.idx.txt”的文件中,其中 idx 每次达到外流最大大小时都会增加(因此您将获得 5文件)。

和班级本身:

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();
    }
}

【讨论】:

  • 输出也有限。我最多可以写1G。如果我有更多的开始运行到其他输出流
【解决方案2】:

恐怕你原来的question没有得到充分的解释,所以你得到的答案也没有。

您不应该使用或扩展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);

【讨论】:

  • 我很确定从多个线程使用 OutputStream 需要同步。
  • @VGR 这一点需要小心,但答案是否定的:BufferedOutputStream 的所有方法都已经是synchronized
【解决方案3】:

我想您可以尝试将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);
}

【讨论】:

    猜你喜欢
    • 2018-10-28
    • 1970-01-01
    • 2012-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 2017-03-28
    • 2013-05-11
    相关资源
    最近更新 更多