Processing a text file line by line is a common thing programmers do. There are many related classes in the Java I/O package and this may get confusing. This post shows 4 different ways of reading a file line by line in Java.
1. FileInputStream and BufferedReader
private static void readFile1(File fin) throws IOException { FileInputStream fis = new FileInputStream(fin); //Construct BufferedReader from InputStreamReader BufferedReader br = new BufferedReader(new InputStreamReader(fis)); String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); } |
2. FileReader and BufferedReader
private static void readFile2(File fin) throws IOException { // Construct BufferedReader from FileReader BufferedReader br = new BufferedReader(new FileReader(fin)); String line = null; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); } |
Use the following code:
//use . to get current directory File dir = new File("."); File fin = new File(dir.getCanonicalPath() + File.separator + "in.txt"); readFile1(fin); readFile2(fin); |
Both works for reading a text file line by line.
The difference between the two methods is how to construct a BufferedReader object. Method 1 uses InputStreamReader and Method 2 uses FileReader. What’s the difference between the two classes? An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. InputStreamReader can handle other input streams than files, such as network connections, classpath resources, ZIP files, etc.
FileReader is a convenience class for reading character files. The constructors of this class assume that the default character encoding and the default byte-buffer size are appropriate. FileReader does not allow you to specify an encoding other than the platform default encoding. Therefore, it is not a good idea to use it if the program will run on systems with different platform encoding.
Comparing Method 1 & 2, InputStreamReader is a safer choice than FileReader.
3. Files.newBufferedReader()
You can also use the following method which is available since Java 1.7. Essentially, it is the same with Method 1.
Charset charset = Charset.forName("US-ASCII"); try (BufferedReader reader = Files.newBufferedReader(file, charset)) { String line = null; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException x) { System.err.format("IOException: %s%n", x); } |
The newBufferedReader() method does the following:
public static BufferedReader newBufferedReader(Path path, Charset cs){ CharsetDecoder decoder = cs.newDecoder(); Reader reader = new InputStreamReader(newInputStream(path), decoder); return new BufferedReader(reader); } |
4. Lambda in Java 8
From Java 8, we can use a single line to read a file line by line.
Files.lines(new File("test.txt").toPath()).map(s -> s.trim()) .filter(s -> s.startsWith("abc") .forEach(System.out::println); |
Reading the class hierarchy diagram is also very helpful for understanding those inputstream and reader related concept: http://www.programcreek.com/2012/05/java-io-class-hierarchy-diagram/.
Without buffering, each invocation of read() or readLine() could cause bytes to be read from the file, converted into characters, and then returned, which can be very inefficient. It is therefore advisable to wrap a BufferedReader around any Reader.
https://knpcode.com/java-programs/how-to-read-file-in-java/
In the fourth example there is a small mistake – missing bracket. Correct:
.filter(s -> s.startsWith(“abc”))
Don’t i need fis.close() before br.close()??
Scanner and Printwriter are more convenient IMO. Both Byte Stream and Character Stream are lower level implementations.
may be it is too late feedback but when I tried them BufferedReader method close() also is throwable exception
Thanks