Recently I've faced an issue in one of our project that the input stream has been used twice and the usage of second occurance has caused an issue.Of course, I've resolved the problem and I'm going to explain here the problem and solution.

If there're situations to use single input stream twice, we should be very careful as the second usage might not work as you expect. Let me explain you with an example.

We would like to copy a file into two different output streams. So, naturally we'll go for a FileInputStream and two different FileOutputStream objects as below

CopyMultipleFiles.java

/**
* A demo class to explain reading data from streams
* @author Santhosh Reddy Mandadi
* @since 14-Jun-2012
* @version 1.0
*/
import java.io.*;

public class CopyMultipleFiles
{
public static void main(String args[]) throws Exception
{
FileInputStream fis = new FileInputStream("CopyMultipleFiles.java");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos1 = new FileOutputStream("FileCopy1.java");
FileOutputStream fos2 = new FileOutputStream("FileCopy2.java");
copyBytes(bis, fos1);
System.out.println("FileCopy1 has copied successfully...");
copyBytes(bis, fos2);
System.out.println("FileCopy2 has copied successfully...");
bis.close();
fis.close();
}
public static void copyBytes(InputStream fis, OutputStream fos) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(fos));
String str = br.readLine();
while(str!=null)
{
wr.write(str+System.getProperty("line.separator"));
str = br.readLine();
}
wr.close();
}
}

Guess, what will be the output for this program?

You would expect two files to be copied properly, but that doesn't happen as we've completely read through file when we copy the file for the first time. i.e.; when we start the copying process second time, the cursor is at the end of the file.

We should use marking concept to solve this problem. Here is the solution

CopyMultipleFiles.java

/**
* A demo class to explain reading data from streams
* @author Santhosh Reddy Mandadi
* @since 14-Jun-2012
* @version 1.0
*/
import java.io.*;

public class CopyMultipleFiles
{
public static void main(String args[]) throws Exception
{
InputStream fis = new FileInputStream("CopyMultipleFiles.java");
BufferedInputStream bis = new BufferedInputStream(fis);
int size = (int)new File("CopyMultipleFiles.java").length();
System.out.println(bis.markSupported());
bis.mark(size+1);
FileOutputStream fos1 = new FileOutputStream("FileCopy1.java");
FileOutputStream fos2 = new FileOutputStream("FileCopy2.java");
copyBytes(bis, fos1);
System.out.println("FileCopy1 has copied successfully...");
bis.reset();
copyBytes(bis, fos2);
System.out.println("FileCopy2 has copied successfully...");
fis.close();
}
public static void copyBytes(InputStream fis, OutputStream fos) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(fos));
String str = br.readLine();
while(str!=null)
{
wr.write(str+System.getProperty("line.separator"));
str = br.readLine();
}
wr.close();
fos.close();
}
}

When BufferedInputStream object is created, the file readers position is at the before begining of the file. I've used mark method as soon as the object is created. So, mark is created at the before begining of the file. And we'll be reading the file and copying the bytes using copyBytes method. After the end of copyBytes method, the buffered reader position will be at the after end of the file. Here, I've used bis.reset() method to go back to the position of what has been marked previously. So, the reader's position will go back to the first position of the file.

Note: mark() method accepts an integer number represents number of bytes which need to be read before destorying this mark. So, mark method will be destroyed after reading the number of bytes passed as an argument.