写入具有容量限制

时间:2015-10-08 14:42:10

标签: java outputstream capacity

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

  1. 当我在输出流中写出比1MB更多的内容时,我需要"停止"。 我不想抛出异常,而是写出os的完整内容 输出流到指定的其他输出流参数。 OutputStream out; os.writeTo(out); 之后继续从os开始写作

  2. 为了防止1中描述的情况,我更倾向于排空os, 尽可能自由。我的意思是将数据从它复制到chuncks中的out 512KB 这可行吗?如果是,任何建议怎么办?或者可能有一个内置的课程来满足我的要求

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

3 个答案:

答案 0 :(得分:6)

您所描述的是BufferedOutputStream,您可以像这样构建:

new BufferedOutputStream(out, 512000)

第一个arg是你拥有的另一个输出流,第二个是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个文件)。

和类intself:

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

答案 1 :(得分:2)

我担心您原来的question没有得到充分解释,所以不是您得到的答案。

你不应该使用或扩展BytArrayOutputStream进行刷新,因为它的主要特征是将数据写入一个字节数组&#34 ;:即:所有数据都是在内存中,因此您可以稍后通过identity := fmt.Sprintf("cat %s/.ssh/%s.pub", fileUtil.FindUserHomeDir(), p.sshkey.name) address := fmt.Sprintf("| ssh %s@%s 'cat >> ~/.ssh/authorized_keys', p.projectname.name, p.host.name) cmd := exec.Command(identity, address) err := cmd.Run() if err != nil { log.Fatal(err) } 检索它。

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

cat /home/foo/.ssh/foobar.pub | ssh foo@bar.com 'cat >> ~/.shh/authorized_keys'"

为了定期刷新数据,您可以安排TimerTask调用toByteArray

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

答案 2 :(得分:1)

我猜您可以尝试将java.nio.ByteBufferjava.nio.channel.Channels结合使用方法newChannel(OutputStream);

像这样:

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