简体   繁体   中英

Reading OKIO stream twice

I am using OKHTTP for networking and currently get a charStream from response.charStream() which I then pass for GSON for parsing. Once parsed and inflated, I deflate the model again to save to disk using a stream. It seems like extra work to have to go from networkReader to Model to DiskWriter. Is it possible with OKIO to instead go from networkReader to JSONParser(reader) as well as networkReader to DiskWriter(reader). Basically I want to to be able to read from the network stream twice.

You can use a MirroredSource (taken from this gist ).

public class MirroredSource {

    private final Buffer buffer = new Buffer();
    private final Source source;
    private final AtomicBoolean sourceExhausted = new AtomicBoolean();

    public MirroredSource(final Source source) {
        this.source = source;
    }

    public Source original() {
        return new okio.Source() {

            @Override
            public long read(final Buffer sink, final long byteCount) throws IOException {
                final long bytesRead = source.read(sink, byteCount);
                if (bytesRead > 0) {
                    synchronized (buffer) {
                        sink.copyTo(buffer, sink.size() - bytesRead, bytesRead);
                        // Notfiy the mirror to continue
                        buffer.notify();
                    }
                } else {
                    sourceExhausted.set(true);
                }
                return bytesRead;
            }

            @Override
            public Timeout timeout() {
                return source.timeout();
            }

            @Override
            public void close() throws IOException {
                source.close();
                sourceExhausted.set(true);
                synchronized (buffer) {
                    buffer.notify();
                }
            }
        };
    }

    public Source mirror() {
        return new okio.Source() {

            @Override
            public long read(final Buffer sink, final long byteCount) throws IOException {
                synchronized (buffer) {
                    while (!sourceExhausted.get()) {
                        // only need to synchronise on reads when the source is not exhausted.

                        if (buffer.request(byteCount)) {
                            return buffer.read(sink, byteCount);
                        } else {
                            try {
                                buffer.wait();
                            } catch (final InterruptedException e) {
                                //No op
                            }
                        }
                    }
                }
                return buffer.read(sink, byteCount);
            }

            @Override
            public Timeout timeout() {
                return new Timeout();
            }

            @Override
            public void close() throws IOException { /* not used */ }
        };
    }
}

Usage would look like:

MirroredSource mirroredSource = new MirroredSource(response.body().source()); //Or however you're getting your original source
Source originalSource = mirroredSource.original();
Source secondSource = mirroredSource.mirror();
doParsing(originalSource);
writeToDisk(secondSource);
originalSource.close();

If you want something more robust you can repurpose Relay from OkHttp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM