How can I make a copy of a BufferedReader?
Asked Answered
S

3

16

I am using a BufferedReader constructor to make a new copy of an existing BufferedReader.

BufferedReader buffReader = new BufferedReader(originalBuffReader);

The new buffReader is working fine, but when I do originalBuffReader.readLine() it gives me null. Is there any other way I can make a new bufferReader without affecting my original BufferedReader.

FYI: I am getting bufferReader as an input to my method; and I do not have a access to the source.

Slunk answered 24/8, 2012 at 9:52 Comment(1)
What exactly do you mean by 'copy of a BufferedReader'? Are you expecting somehow to be able to read the same stream twice? It's not possible. In fact it is a contradiction in terms.Vulcan
T
17

Any other way I can make a new bufferReader without affecting my oroginal BufferReader

There's no straight forward way of solving it by just creating two BufferedReaders. (The two readers will consume data from the same source.) You'll have to add another level of buffering on the source, so each reader can read the stream independently.

This can be achieved by combining TeeInputStream from Apache Commons and a PipedInputStream and PipedOutputStream as follows:

import java.io.*;
import org.apache.commons.io.input.TeeInputStream;
class Test {
    public static void main(String[] args) throws IOException {

        // Create the source input stream.
        InputStream is = new FileInputStream("filename.txt");

        // Create a piped input stream for one of the readers.
        PipedInputStream in = new PipedInputStream();

        // Create a tee-splitter for the other reader.
        TeeInputStream tee = new TeeInputStream(is, new PipedOutputStream(in));

        // Create the two buffered readers.
        BufferedReader br1 = new BufferedReader(new InputStreamReader(tee));
        BufferedReader br2 = new BufferedReader(new InputStreamReader(in));

        // Do some interleaved reads from them.
        System.out.println("One line from br1:");
        System.out.println(br1.readLine());
        System.out.println();

        System.out.println("Two lines from br2:");
        System.out.println(br2.readLine());
        System.out.println(br2.readLine());
        System.out.println();

        System.out.println("One line from br1:");
        System.out.println(br1.readLine());
        System.out.println();
    }
}

Output:

One line from br1:
Line1: Lorem ipsum dolor sit amet,      <-- reading from start

Two lines from br2:
Line1: Lorem ipsum dolor sit amet,      <-- reading from start
Line2: consectetur adipisicing elit,

One line from br1:
Line2: consectetur adipisicing elit,    <-- resumes on line 2
Took answered 24/8, 2012 at 9:55 Comment(4)
Thanks aioobe for ur reply , Actually I am getting a bufferReader as a input to my methode so I have to make a copy using that bufferReader do not have access to source.Slunk
Then I would create a wrapper that wraps the given buffered reader, buffers the read lines and deals out secondary readers, which read from the buffer. (Unless you have the option of draining the data completely into a List<String> and use that instead.) (I'm curious, which API only gives you a BufferedReader?)Took
BufferReader is filled up from the source somewhere and passed through a method as a parameter and I have to take it from there.Slunk
Be aware by copy pasting this code. This works not in any case. For example if the InputStream comes from ClassLoader.getSystemResourceAsStream("myResource") it will get stuck.Concessive
B
3

Below is one way to consider creating a new BufferedReader out of the Original BufferedReader.

Essentially, we are dumping the contents of the original buffered reader into a string and then recreating a new BufferedReader object. To be able to re read the original BufferedReader a second time you can mark it and then after reading it, you can then reset it.

One thing to keep in mind is you might want to protect by DDOS attacks, where a very large buffered reader can come in and you might want to avoid reading for ever and filling up the memory, you can basically break the for loop after some point or when a certain condition is met.

final String originalBufferedReaderDump;
originalBufferedReaderDump.mark(Integer.MAX_VALUE);
for (String line; (line = originalBufferedReader.readLine()) != null; originalBufferedReaderDump+= line);
originalBufferedReader.reset();
final BufferedReader copiedBufferedReader  = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(originalBufferedReaderDump.getBytes())));
Bort answered 18/10, 2017 at 17:46 Comment(0)
B
2

Passing in a BufferedReader instance in the constructor for a new BufferedReader will not make a copy of the original BufferedReader!

What you are doing there is chaining the two reader, in other words, you are buffering the already buffered reader instance. When you call readLine() on buffReader, it will call readLine() on originalBuffReader.

Take a look here for more details of the chaining of streams: Chaining of Streams

Burke answered 24/8, 2012 at 9:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.