Java Tutorial 0/145 lessons ~6 min read Lesson 28

    Java I/O Streams

    java IO input output streams InputStream OutputStream FileReader BufferedReader NIO channels buffers serialization

    Course progress0%
    Focus
    31 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    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:

    code
    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

    code
    Object
    ┌────────────┴─────────────┐
    │ │
    InputStream OutputStream
    │ │
    FileInputStream FileOutputStream
    BufferedInputStream BufferedOutputStream
    DataInputStream DataOutputStream
    ObjectInputStream ObjectOutputStream
    PrintStream

    Character Streams:

    code
    Reader
    FileReader
    BufferedReader
    InputStreamReader
    code
    Writer
    FileWriter
    BufferedWriter
    PrintWriter

    Byte Streams

    Byte Streams process binary data.

    Examples:

    • Images
    • PDF
    • Audio
    • Video
    • ZIP Files

    Classes:

    • InputStream
    • OutputStream

    InputStream

    Reads bytes.

    code
    FileInputStream input =
    new FileInputStream("sample.txt");
    int data;
    while((data = input.read()) != -1){
    System.out.print((char)data);
    }
    input.close();

    OutputStream

    Writes bytes.

    code
    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

    code
    FileReader reader =
    new FileReader("sample.txt");
    int character;
    while((character = reader.read()) != -1){
    System.out.print((char)character);
    }
    reader.close();

    FileWriter

    code
    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:

    code
    Read
    Disk Access
    Read
    Disk Access

    With Buffer:

    code
    Large Buffer
    Single Disk Access
    Memory Reads

    Much faster.

    BufferedReader

    code
    BufferedReader reader =
    new BufferedReader(
    new FileReader("sample.txt"));
    String line;
    while((line = reader.readLine()) != null){
    System.out.println(line);
    }
    reader.close();

    BufferedWriter

    code
    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:

    code
    DataOutputStream output =
    new DataOutputStream(
    new FileOutputStream("data.dat"));
    output.writeInt(100);
    output.writeDouble(99.5);
    output.close();

    Reading:

    code
    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:

    code
    ObjectOutputStream output =
    new ObjectOutputStream(
    new FileOutputStream("employee.ser"));
    output.writeObject(employee);
    output.close();

    Reading Objects:

    code
    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:

    code
    PrintStream output =
    new PrintStream("report.txt");
    output.println("Employee Report");
    output.println("Total : 150");
    output.close();

    System.out is itself a PrintStream.

    PrintWriter

    code
    PrintWriter writer =
    new PrintWriter("employees.txt");
    writer.println("Rahul");
    writer.println("Amit");
    writer.close();

    Suitable for writing formatted character data.

    InputStream vs Reader

    InputStreamReader
    Byte-basedCharacter-based
    Binary FilesText Files
    ImagesText
    PDFXML
    AudioJSON

    OutputStream vs Writer

    OutputStreamWriter
    BytesCharacters
    Binary DataText Data

    NIO vs Traditional I/O

    Traditional I/O:

    code
    FileReader
    FileWriter

    Modern NIO:

    code
    Path
    Files
    Channels
    Buffers

    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.

    code
    Application
    Channel
    File

    Unlike streams, many channels support reading and writing.

    Buffers

    Channels work with Buffers.

    code
    File
    Channel
    Buffer
    Application

    Buffers reduce unnecessary disk access and improve performance.

    Try-with-Resources

    Always use:

    code
    try(BufferedReader reader =
    new BufferedReader(
    new FileReader("sample.txt"))){
    System.out.println(
    reader.readLine());
    }

    Resources close automatically.

    Real-World Example: Reading Configuration

    code
    Properties properties =
    new Properties();
    try(FileReader reader =
    new FileReader(
    "application.properties")){
    properties.load(reader);
    }

    Real-World Example: Copying a File

    code
    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:

    1. Reads a text file using FileReader.
    2. Reads the same file using BufferedReader.
    3. Writes data using FileWriter.
    4. Writes formatted output using PrintWriter.
    5. Reads and writes primitive data using DataInputStream and DataOutputStream.
    6. Serializes and deserializes an object.
    7. Copies a file using Files.copy().
    8. Reads a configuration file using Properties.
    9. Uses try-with-resources.
    10. 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.

    Ready to mark this lesson complete?Track your journey across the entire course.