Java I/O Streams
java IO input output streams InputStream OutputStream FileReader BufferedReader NIO channels buffers serialization
Introduction
In the previous lessons, you learned about Java File Handling and Java Annotations. You saw how Java applications can create, read, and write files.
However, file handling is only one part of Java's Input/Output system.
Almost every enterprise application performs Input/Output (I/O) operations.
Examples:
- Reading configuration files
- Downloading files
- Uploading images
- Reading data from databases
- Sending data over the network
- Processing CSV, JSON, and XML files
- Reading user input
- Logging application events
- Streaming videos
- Reading Kafka messages
Java provides a powerful I/O API to perform all these operations efficiently.
Java I/O is one of the core concepts behind:
- Spring Boot
- REST APIs
- Microservices
- File Upload Systems
- Banking Applications
- Messaging Systems
- Networking
- Distributed Systems
In this lesson, you'll learn:
- What is Java I/O?
- Stream Architecture
- Byte Streams
- Character Streams
- InputStream
- OutputStream
- Reader
- Writer
- Buffered Streams
- Data Streams
- Object Streams
- Print Streams
- NIO vs Traditional I/O
- Channels & Buffers
- Best Practices
- Common Mistakes
- Hands-on Exercises
- Professional Interview Questions
What is Java I/O?
Java I/O (Input/Output) is the mechanism used to transfer data between a Java application and external resources.
External resources include:
- Files
- Keyboard
- Network
- Database
- Printer
- Memory
- Socket
Example:
Application↓Input Stream↓Processing↓Output Stream↓File
What is a Stream?
A Stream is a sequence of data flowing between a source and a destination.
Streams are one-way.
- Input Stream → Read Data
- Output Stream → Write Data
Java I/O Architecture
Object│┌────────────┴─────────────┐│ │InputStream OutputStream│ │FileInputStream FileOutputStreamBufferedInputStream BufferedOutputStreamDataInputStream DataOutputStreamObjectInputStream ObjectOutputStreamPrintStream
Character Streams:
Reader↓FileReader↓BufferedReader↓InputStreamReader
Writer↓FileWriter↓BufferedWriter↓PrintWriter
Byte Streams
Byte Streams process binary data.
Examples:
- Images
- Audio
- Video
- ZIP Files
Classes:
- InputStream
- OutputStream
InputStream
Reads bytes.
FileInputStream input =new FileInputStream("sample.txt");int data;while((data = input.read()) != -1){System.out.print((char)data);}input.close();
OutputStream
Writes bytes.
FileOutputStream output =new FileOutputStream("sample.txt");output.write('A');output.close();
Character Streams
Character Streams process text data.
Classes:
- Reader
- Writer
Suitable for:
- Text Files
- JSON
- XML
- CSV
- Properties Files
FileReader
FileReader reader =new FileReader("sample.txt");int character;while((character = reader.read()) != -1){System.out.print((char)character);}reader.close();
FileWriter
FileWriter writer =new FileWriter("sample.txt");writer.write("Hello Java");writer.close();
Buffered Streams
Buffered Streams improve performance by reducing physical I/O operations.
Without Buffer:
Read↓Disk Access↓Read↓Disk Access
With Buffer:
Large Buffer↓Single Disk Access↓Memory Reads
Much faster.
BufferedReader
BufferedReader reader =new BufferedReader(new FileReader("sample.txt"));String line;while((line = reader.readLine()) != null){System.out.println(line);}reader.close();
BufferedWriter
BufferedWriter writer =new BufferedWriter(new FileWriter("sample.txt"));writer.write("Spring Boot");writer.newLine();writer.write("Microservices");writer.close();
Data Streams
Used for reading and writing Java primitive data types.
Writing:
DataOutputStream output =new DataOutputStream(new FileOutputStream("data.dat"));output.writeInt(100);output.writeDouble(99.5);output.close();
Reading:
DataInputStream input =new DataInputStream(new FileInputStream("data.dat"));System.out.println(input.readInt());System.out.println(input.readDouble());input.close();
Object Streams
Used for Serialization.
Writing Objects:
ObjectOutputStream output =new ObjectOutputStream(new FileOutputStream("employee.ser"));output.writeObject(employee);output.close();
Reading Objects:
ObjectInputStream input =new ObjectInputStream(new FileInputStream("employee.ser"));Employee employee =(Employee) input.readObject();input.close();
The class must implement the Serializable interface.
PrintStream
Used for formatted output.
Example:
PrintStream output =new PrintStream("report.txt");output.println("Employee Report");output.println("Total : 150");output.close();
System.out is itself a PrintStream.
PrintWriter
PrintWriter writer =new PrintWriter("employees.txt");writer.println("Rahul");writer.println("Amit");writer.close();
Suitable for writing formatted character data.
InputStream vs Reader
| InputStream | Reader |
|---|---|
| Byte-based | Character-based |
| Binary Files | Text Files |
| Images | Text |
| XML | |
| Audio | JSON |
OutputStream vs Writer
| OutputStream | Writer |
|---|---|
| Bytes | Characters |
| Binary Data | Text Data |
NIO vs Traditional I/O
Traditional I/O:
FileReaderFileWriter
Modern NIO:
PathFilesChannelsBuffers
Advantages of NIO:
- Better performance
- Scalable
- Non-blocking capabilities
- Suitable for enterprise applications
Channels
A Channel represents a connection to a file, socket, or device.
Application↓Channel↓File
Unlike streams, many channels support reading and writing.
Buffers
Channels work with Buffers.
File↓Channel↓Buffer↓Application
Buffers reduce unnecessary disk access and improve performance.
Try-with-Resources
Always use:
try(BufferedReader reader =new BufferedReader(new FileReader("sample.txt"))){System.out.println(reader.readLine());}
Resources close automatically.
Real-World Example: Reading Configuration
Properties properties =new Properties();try(FileReader reader =new FileReader("application.properties")){properties.load(reader);}
Real-World Example: Copying a File
Files.copy(Path.of("source.pdf"),Path.of("backup.pdf"));
Best Practices
Prefer Buffered Streams
They reduce disk access and improve performance.
Use Character Streams for Text
Use Reader and Writer when working with text.
Use Byte Streams for Binary Data
Use InputStream and OutputStream for images, PDFs, audio, and other binary content.
Prefer NIO for Modern Applications
Use the java.nio.file package whenever practical.
Always Close Resources
Use try-with-resources to avoid resource leaks.
Common Mistakes
Using FileReader for Images
Use byte streams for binary files.
Forgetting to Close Streams
Can cause memory leaks and locked files.
Ignoring Character Encoding
Specify UTF-8 or another appropriate charset when needed.
Reading Large Files Character by Character
Use buffered streams or NIO APIs for efficiency.
Mixing Byte and Character Streams Incorrectly
Choose the correct stream type based on the data being processed.
Hands-on Exercise
Create a Java program that:
- Reads a text file using
FileReader. - Reads the same file using
BufferedReader. - Writes data using
FileWriter. - Writes formatted output using
PrintWriter. - Reads and writes primitive data using
DataInputStreamandDataOutputStream. - Serializes and deserializes an object.
- Copies a file using
Files.copy(). - Reads a configuration file using
Properties. - Uses try-with-resources.
- Compares traditional I/O with NIO.
Summary
Java I/O provides a comprehensive set of APIs for transferring data between applications and external resources. Byte streams are used for binary data, while character streams are designed for text. Buffered streams improve performance, object streams support serialization, and the NIO API offers modern, efficient file operations using channels and buffers. Choosing the appropriate I/O mechanism is essential for building scalable enterprise applications.
Key Takeaways
- Java I/O transfers data between applications and external resources.
- Streams are one-way data channels.
- Byte streams handle binary data.
- Character streams handle text data.
- Buffered streams improve performance.
- Data streams read and write primitive types.
- Object streams support serialization.
- PrintWriter simplifies formatted text output.
- NIO provides modern, high-performance I/O APIs.
- Try-with-resources helps prevent resource leaks.
Professional Interview Questions
1What is the difference between Byte Streams and Character Streams?
Professional Answer
Byte streams process raw binary data and are represented by InputStream and OutputStream. They are suitable for files such as images, videos, PDFs, and ZIP archives. Character streams process Unicode text using Reader and Writer, making them appropriate for text files, JSON, XML, CSV, and other character-based formats.
Follow-up Questions
- Which stream would you use for a JPEG image?
- Which stream would you use for a CSV file?
Interview Tip: Remember: Byte Streams → Binary Data, Character Streams → Text Data.
2Why is BufferedReader faster than FileReader?
Professional Answer
BufferedReader reads data into an internal memory buffer, significantly reducing the number of physical I/O operations required. It also provides convenient methods such as readLine(). In contrast, FileReader reads characters directly from the file and is generally less efficient for large text files.
Follow-up Questions
- What is buffering?
- What is the purpose of BufferedWriter?
Interview Tip: Buffering = Fewer Disk Accesses = Better Performance.
3What is the difference between Traditional I/O and Java NIO?
Professional Answer
Traditional Java I/O is stream-based and processes data sequentially through InputStream, OutputStream, Reader, and Writer. Java NIO introduces Path, Files, Channels, and Buffers, providing better scalability, improved performance, richer file APIs, and support for non-blocking I/O in networking applications.
Follow-up Questions
- What are Channels?
- What are Buffers?
- Why is NIO preferred in modern Java applications?
Interview Tip: Traditional I/O → Streams, Java NIO → Channels + Buffers + Path + Files.