User Tools

Site Tools


java_i_o_streams

Java I/O Streams

Return to Java Reading and Writing Files

Using I/O Streams

I/O streams are all about reading/writing data, so it shouldn't be a surprise that the most important methods are read() and write(). Both InputStream and Reader declare a read() method to read byte data from an I/O stream. Likewise, OutputStream and Writer both define a write() method to write a byte to the stream:

The following copyStream() methods show an example of reading all of the values of an InputStream and Reader and writing them to an OutputStream and Writer, respectively. In both examples, -1 is used to indicate the end of the stream.

void copyStream(InputStream in, OutputStream out) throws IOException { int b; while 1) != -1) { out.write(b); } } void copyStream(Reader in, Writer out) throws IOException { int b; while 2) != -1) { out.write(b); } }

Hold on. We said we are reading and writing bytes, so why do the methods use int instead of byte? Remember, the byte data type has a range of 256 characters. They needed an extra value to indicate the end of an I/O stream. The authors of Java decided to use a larger data type, int, so that special values like -1 would indicate the end of an I/O stream. The output stream classes use int as well, to be consistent with the input stream classes.

Reading and writing one byte at a time isn't a particularly efficient way of doing this. Luckily, there are overloaded methods for reading and writing multiple bytes at a time. The offset and length values are applied to the array itself. For example, an offset of 3 and length of 5 indicates that the stream should read up to five bytes/characters of data and put them into the array starting with position 3. Let's look at an example:

10: void copyStream(InputStream in, OutputStream out) throws IOException { 11: int batchSize = 1024; 12: var buffer = new byte[batchSize]; 13: int lengthRead; 14: while 3)> 0) { 15: out.write(buffer, 0, lengthRead); 16: out.flush(); 17: }

Instead of reading the data one byte at a time, we read and write up to 1024 bytes at a time on line 14. The return value lengthRead is critical for determining whether we are at the end of the stream and knowing how many bytes we should write into our output stream.

Unless our file happens to be a multiple of 1024 bytes, the last iteration of the while loop will write some value less than 1024 bytes. For example, if the buffer size is 1,024 bytes and the file size is 1,054 bytes, the last read will be only 30 bytes. If we ignored this return value and instead wrote 1,024 bytes, 994 bytes from the previous loop would be written to the end of the file.

We also added a flush() method on line 16 to reduce the amount of data lost if the application terminates unexpectedly. When data is written to an output stream, the underlying operating system does not guarantee that the data will make it to the file system immediately. The flush() method requests that all accumulated data be written immediately to disk. It is not without cost, though. Each time it is used, it may cause a noticeable delay in the application, especially for large files. Unless the data that you are writing is extremely critical, the flush() method should be used only intermittently. For example, it should not necessarily be called after every write, as it is in this example.

Equivalent methods exist on Reader and Writer, but they use char rather than byte, making the equivalent copyStream() method very similar.

The previous example makes reading and writing a file look like a lot to think about. That's because it only uses low-level I/O streams. Let's try again using high-level streams.

26: void copyTextFile(File src, File dest) throws IOException { 27: try (var reader = new BufferedReader(new FileReader(src)); 28: var writer = new BufferedWriter(new FileWriter(dest))) { 29: String line = null; 30: while 4) != null) { 31: writer.write(line); 32: writer.newLine(); 33: } } }

The key is to choose the most useful high-level classes. In this case, we are dealing with a File, so we want to use a FileReader and FileWriter. Both classes have constructors that can take either a String representing the location or a File directly.

If the source file does not exist, a FileNotFoundException, which inherits IOException, will be thrown. If the destination file already exists, this implementation will overwrite it. We can pass an optional boolean second parameter to FileWriter for an append flag if we want to change this behavior.

We also chose to use a BufferedReader and BufferedWriter so we can read a whole line at a time. This gives us the benefits of reading batches of characters on line 30 without having to write custom logic. Line 31 writes out the whole line of data at once. Since reading a line strips the line breaks, we add those back on line 32. Lines 27 and 28 demonstrate chaining constructors. The try-with-resources constructor takes care of closing all the objects in the chain.

Now imagine that we wanted byte data instead of characters. We would need to choose different high-level classes: BufferedInputStream, BufferedOutputStream, FileInputStream, and FileOuputStream. We would call readAllBytes() instead of readLine() and store the result in a byte[] instead of a String. Finally, we wouldn't need to handle new lines since the data is binary.

We can do a little better than BufferedOutputStream and BufferedWriter by using a PrintStream and PrintWriter. These classes contain four key methods. The print() and println() methods print data with and without a new line, respectively. There are also the format() and printf() methods, which we describe in the section on user interactions.

void copyTextFile(File src, File dest) throws IOException { try (var reader = new BufferedReader(new FileReader(src)); var writer = new PrintWriter(new FileWriter(dest))) { String line = null; while 5) != null) writer.println(line); } }

While we used a String, there are numerous overloaded versions of println(), which take everything from primitives and String values to objects. Under the covers, these methods often just perform String.valueOf().

The print stream classes have the distinction of being the only I/O stream classes we cover that do not have corresponding input stream classes. And unlike other OutputStream classes, PrintStream does not have Output in its name.

It may surprise you that you've been regularly using a PrintStream throughout this book. Both System.out and System.err are PrintStream objects. Likewise, System.in, often useful for reading user input, is an InputStream.

Unlike the majority of the other I/O streams we've covered, the methods in the print stream classes do not throw any checked exceptions. If they did, you would be required to catch a checked exception any time you called System.out.print()!

The line separator is \n or \r\n, depending on your operating system. The println() method takes care of this for you. If you need to get the character directly, either of the following will return it for you:

System.getProperty(“line.separator”); System.lineSeparator();

Java: Java Fundamentals, Java Inventor - Java Language Designer: James Gosling of Sun Microsystems, Java Docs, JDK, JVM, JRE, Java Keywords, JDK 17 API Specification, java.base, Java Built-In Data Types, Java Data Structures - Java Algorithms, Java Syntax, Java OOP - Java Design Patterns, Java Installation, Java Containerization, Java Configuration, Java Compiler, Java Transpiler, Java IDEs (IntelliJ - Eclipse - NetBeans), Java Development Tools, Java Linter, JetBrains, Java Testing (JUnit, Hamcrest, Mockito), Java on Android, Java on Windows, Java on macOS, Java on Linux, Java DevOps - Java SRE, Java Data Science - Java DataOps, Java Machine Learning, Java Deep Learning, Functional Java, Java Concurrency, Java History,

Java Bibliography (Effective Java, Head First Java, Java - A Beginner's Guide by Herbert Schildt, Java Concurrency in Practice, Clean Code by Robert C. Martin, Java - The Complete Reference by Herbert Schildt, Java Performance by Scott Oaks, Thinking in Java, Java - How to Program by Paul Deitel, Modern Java in Action, Java Generics and Collections by Maurice Naftalin, Spring in Action, Java Network Programming by Elliotte Rusty Harold, Functional Programming in Java by Pierre-Yves Saumont, Well-Grounded Java Developer, Second Edition, Java Module System by Nicolai Parlog

), Manning Java Series, Java Glossary, Java Topics, Java Courses, Java Security - Java DevSecOps, Java Standard Library, Java Libraries, Java Frameworks, Java Research, Java GitHub, Written in Java, Java Popularity, Java Awesome List, Java Versions. (navbar_java and navbar_java_detailed - see also navbar_jvm, navbar_java_concurrency, navbar_java_standard_library, navbar_java_libraries, navbar_java_navbars)


© 1994 - 2024 Cloud Monk Losang Jinpa or Fair Use. Disclaimers

SYI LU SENG E MU CHYWE YE. NAN. WEI LA YE. WEI LA YE. SA WA HE.


1) , 2)
b = in.read(
3)
lengthRead = in.read(buffer, 0, batchSize
4) , 5)
line = reader.readLine(
java_i_o_streams.txt · Last modified: 2024/04/28 03:39 (external edit)