Input/Output in JAVA

Understanding BufferedReader

To print something on the console in java we have `System.out.println()' breaking this statement down

  • println() is actually a method of one PrintStream Class

  • `out` is actually Object of PrintStream class, it is a static member variable for the System class

  • Hence System.out.println() could be explained

Now take the input from the user, we have similar functionality in JAVA

System.in.read()
  • Above in is a static member variable in System class

  • read returns an integer and throws a checked exception

  • The problem is this returns the ASCII value of the number we enter - we dont want that and also this can only ready one character at a time

So instead of using above java provides us with a dedicated class known as BufferedReader from the JAVA IO package

  • this needs a Reader Object as an argument, InputStream Reader

  • InputStream reader needs an object of InputStream ! - we can pass System.in

  •       InputStreamReader in = new InputStreamReader (System.in)
          BufferedReader bf = new BufferedReader (in);
          int num = Integer.parseInt(bf.readLine()) ;
          bf.close();// Dont forget to close the resouce
    

BufferedReader can take input from anywhere not just from keyboard but from the file also

Post Java 5 we prevalently use Scanner class for inputs

Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
System.out.println(num)

Basic Concepts

  1. File: This is an abstract representation of file and directory pathnames.

     File file1 = new File("system file path here");
     // If this file is not present it will NOT be created 
     System.out.println(file1.exists());// false
     try {
         System.out.printin(filel.createNewFile));
         System.out.println(file1.exists());// TRUE
     }
     catch (IOException e) {
         e. printStackTrace;
     }
    
  2. File Handling Classes: Java provides several classes for file handling, including File, FileReader, FileWriter, BufferedReader, BufferedWriter, among others.

Important Classes and Methods

  • File: This class represents file and directory pathnames in an abstract manner.

    • exists(): Checks if file or directory exists.

    • createNewFile(): Creates a new file.If file is present it will not create it again

    • mkdir(): Creates a new directory at the path specified during File creation

    • delete(): Deletes a file or directory.

    • isDirectory(): Checks if path is a directory

    • isFile(): Checks if path is a file

    • getPath(): Returns the path of the file

  • FileReader and FileWriter: For reading and writing character files.

  • BufferedReader and BufferedWriter: For efficient reading and writing of characters, arrays, and lines.

Step-by-Step Examples

1. Creating a File

import java.io.File;
import java.io.IOException;

public class CreateFileExample {
    public static void main(String[] args) {
        File myFile = new File("example.txt");
        try {
            if (myFile.createNewFile()) {
                System.out.println("File created: " + myFile.getName());
            } else {
                System.out.println("File already exists.");
            }
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
}

2. Writing to a File

Using FileWriter to write data into the file.

import java.io.FileWriter;
import java.io.IOException;

public class WriteFileExample {
    public static void main(String[] args) {
        try {
            FileWriter myWriter = new FileWriter("example.txt");
            myWriter.write("Hello, world!\nThis is a file handling example in Java.");
            myWriter.close();
            System.out.println("Successfully wrote to the file.");
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
}

3. Reading from a File

Using FileReader and BufferedReader to read data from the file.

import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;

public class ReadFileExample {
    public static void main(String[] args) {
        try {
            FileReader fileReader = new FileReader("example.txt");
            BufferedReader bufferedReader = new BufferedReader(fileReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
            bufferedReader.close();
            fileReader.close();
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
}

4. Deleting a File

import java.io.File;

public class DeleteFileExample {
    public static void main(String[] args) {
        File myFile = new File("example.txt");
        if (myFile.delete()) {
            System.out.println("Deleted the file: " + myFile.getName());
        } else {
            System.out.println("Failed to delete the file.");
        }
    }
}
  1. Count Number of Files in a Directory

     File file2=new File("D:\\IO\\src");
     String[] str = file2.list();
     int count=0;
     for (String files:str){
         count++;
         System.out.println(files);
     }
    
  2. Writing character, string, character array to a File

         public static void main(String[] args) 
         {
     //        String path1="D:\\IO\\FileHandling\\java.txt";
             String path1="D:\\IO\\FileHandling";
             FileWriter fw=null;
             try
             {
     //            File file=new File(path1);
                 File dir=new File(path1);
                 File file=new File(dir, "java.txt");// dir -> file
                 fw=new FileWriter(file);
                 fw.write("Java");
                 fw.write(65);//'A'
                 char ch[]= {'s', 'q', 'l'};
                 fw.write(ch);
                 System.out.println("Kindly check file in the specified location to see outcome");
    
             }
             catch(Exception e)
             {
                 System.out.println("Something went wrong");
             }
             finally
             {
                 try 
                 {
                     fw.close();
                 } 
                 catch (IOException e) 
                 {
    
                     e.printStackTrace();
                 }
             }
    
         }
    
  3. Reading character data from the File

    ```java public static void main(String[] args) { String path1="D:\IO\FileHandling"; FileReader fr=null; try { // File file=new File(path1); File dir=new File(path1); File file=new File(dir, "java.txt"); fr=new FileReader(file); // METHOD 1 // int i=fr.read(); // while(i!=-1) // { // System.out.println(i+ " --> "+ (char)i); // i=fr.read(); // } // METHOD 2 - Directly reading into character array
    int size = (int)file.length(); char ch[]=new char[size]; fr.read(ch); for(char c:ch){ System.out.println(c); } } catch(Exception e){ System.out.println("Something went wrong"); } finally{ try { fr.close(); } catch (IOException e) {

    e.printStackTrace(); } }

}


8. **Using Buffered Reader (More efficient than FileReader)**

    ```java
        public static void main(String[] args) {
            String path1="D:\\IO\\FileHandling";
            FileReader fr=null;
            BufferedReader br=null;
            try
            {
    //            File file=new File(path1);
                File dir=new File(path1);
                File file=new File(dir, "java.txt");
                fr=new FileReader(file);
                br=new BufferedReader(fr);// TAKES IN FILE READER
                String str=br.readLine();// READS BY LINE INSTEAD OF CHAR
                while(str!=null)
                {
                    System.out.println(str);
                    str=br.readLine();
                }
            }
            catch(Exception e)
            {
                System.out.println("Something went wrong");
            }
            finally
            {
                try 
                {
                    fr.close();
                    br.close();
                } 
                catch (IOException e) 
                {

                    e.printStackTrace();
                }
            }


        }
  1. Using Buffered Writer

     public static void main(String[] args)
         {
    
     //        String path="D:\\IO\\FileHandling\\java.txt";
             String path1="D:\\IO\\FileHandling";
             FileWriter fw=null;
             BufferedWriter bw=null;
             try
             {
     //            File file=new File(path1);
                 File dir=new File(path1);
                 File file=new File(dir, "java.txt");
                 fw=new FileWriter(file);
                 bw=new BufferedWriter(fw);// TAKES IN FILE WRITER
                 bw.write(" Alien");
                 bw.newLine();
                 bw.write(66);// 'B' (NOT 66)
                 bw.write(" CICD/Jenkins");
                 bw.flush();//RECOMMENDED
    
                 System.out.println("Kindly check file in the specified location to see outcome");
    
             }
             catch(Exception e)
             {
                 System.out.println("Something went wrong");
             }
             finally
             {
                 try 
                 {
                     fw.close();
                     bw.close();
                 } 
                 catch (IOException e) 
                 {
    
                     e.printStackTrace();
                 }
             }
    
         }
    
  2. How to write non character data ? - Use PrintWriter

        public static void main(String[] args) throws FileNotFoundException 
        {
            String path1="D:\\IO\\FileHandling";
            File dir=new File(path1);
            File file=new File(dir, "java.txt");
    
            PrintWriter pw=new PrintWriter(file);
            pw.println(true);
            pw.println(44.5);
            pw.println(14);
            pw.println("Java");
    
            pw.close();
    
        }
    

    What is Serialization / Deserialization?

    Serialization is the process of converting an object into a format that can be easily stored or transmitted. This format is typically a byte stream, which can be saved to a file, sent over a network, or stored in a database.

    Deserialization is the reverse process of serialization. It involves converting the byte stream back into a copy of the original object. This allows the object to be reconstructed in memory, retaining its original state and data.

    Problems Solved by Serialization/Deserialization

    1. Persistence: Serialization allows objects to be saved to a file or database, making it possible to persist the state of an application between runs.

    2. Communication: In distributed systems, objects need to be transmitted over a network. Serialization allows objects to be converted into a format that can be easily sent and received.

    3. Caching: Serialized objects can be stored in a cache to improve performance by avoiding the need to recreate objects from scratch.

    4. Deep Copy: Serialization can be used to create a deep copy of an object, which is useful when you need a complete duplicate that is independent of the original.

In Java, serialization is implemented using the java.io.Serializable interface. An object is serializable if its class or any of its superclasses implements this interface. The Serializable interface is a marker interface, meaning it does not contain any methods. It simply indicates that a class can be serialized.

Here’s a step-by-step guide on how serialization and deserialization are implemented in Java:

1. Implementing Serializable Interface

To make a class serializable, it must implement the Serializable interface.

    import java.io.Serializable;

    public class Employee implements Serializable {
        private static final long serialVersionUID = 1L;

        private String name;
        private int id;

        // Constructors, getters, and setters
    }

2. Serializing an Object

To serialize an object, you use ObjectOutputStream along with FileOutputStream.

    import java.io.FileOutputStream;
    import java.io.ObjectOutputStream;
    import java.io.IOException;

    public class SerializeDemo {
        public static void main(String[] args) {
            Employee emp = new Employee("John Doe", 12345);

            try (FileOutputStream fileOut = new FileOutputStream("employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
                out.writeObject(emp);
                System.out.println("Serialized data is saved in employee.ser");
            } catch (IOException i) {
                i.printStackTrace();
            }
        }
    }

3. Deserializing an Object

To deserialize an object, you use ObjectInputStream along with FileInputStream.

    import java.io.FileInputStream;
    import java.io.ObjectInputStream;
    import java.io.IOException;
    import java.io.FileNotFoundException;

    public class DeserializeDemo {
        public static void main(String[] args) {
            Employee emp = null;

            try (FileInputStream fileIn = new FileInputStream("employee.ser");
                 ObjectInputStream in = new ObjectInputStream(fileIn)) {
                emp = (Employee) in.readObject();// downcasting
                System.out.println("Deserialized Employee...");
                System.out.println("Name: " + emp.getName());
                System.out.println("ID: " + emp.getId());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException i) {
                i.printStackTrace();
            } catch (ClassNotFoundException c) {
                System.out.println("Employee class not found");
                c.printStackTrace();
            }
        }
    }

Serialization is a versatile tool used in many real-world applications to solve various problems related to data storage, transmission, and processing. Here are some examples of different real-world applications where serialization is commonly used:

1. Web Applications

Example: User Session Management

  • Problem: In web applications, user sessions need to be maintained across multiple requests. This involves storing user-specific data such as login status, preferences, and shopping cart contents.

  • Solution: Serialization is used to convert the user session object into a byte stream, which can then be stored in a database or in-memory cache (e.g., Redis). When the user makes another request, the session object is deserialized to restore the user's state.

2. Mobile Applications

Example: Offline Data Storage

  • Problem: Mobile applications often need to store data locally to provide offline functionality. This includes user settings, cached data, and application state.

  • Solution: Serialization is used to save objects representing this data to local storage (e.g., SQLite database, file system). When the app is restarted or the device is offline, the data can be deserialized to restore the application state.

3. Distributed Systems

Example: Remote Procedure Calls (RPC)

  • Problem: In distributed systems, different components often need to communicate with each other over a network. This involves sending complex data structures between services.

  • Solution: Serialization is used to convert objects into a format that can be transmitted over the network (e.g., JSON, XML, Protocol Buffers). The receiving service deserializes the data to reconstruct the original object.

4. Game Development

Example: Saving Game State

  • Problem: Games need to save the state of the game, including player progress, inventory, and game settings, so that players can resume from where they left off.

  • Solution: Serialization is used to save the game state to a file or database. When the player resumes the game, the state is deserialized to restore the game to its previous state.

5. Enterprise Applications

Example: Data Caching

  • Problem: Enterprise applications often need to cache data to improve performance and reduce load on databases.

  • Solution: Serialization is used to store objects in a distributed cache (e.g., Memcached, Redis). When the data is needed again, it is deserialized from the cache, reducing the need for repeated database queries.

6. IoT (Internet of Things)

Example: Sensor Data Transmission

  • Problem: IoT devices collect data from sensors and need to transmit this data to a central server for processing and analysis.

  • Solution: Serialization is used to convert sensor data into a format suitable for transmission (e.g., JSON, Protocol Buffers). The central server deserializes the data to process and analyze it.

7. Financial Applications

Example: Transaction Logging

  • Problem: Financial applications need to log transactions for auditing and recovery purposes.

  • Solution: Serialization is used to convert transaction objects into a format that can be stored in a log file or database. In case of a system failure, the transactions can be deserialized to reconstruct the transaction history.

Here’s a brief example of how serialization might be used in a web application for session management:

Key Points to Remember

  • serialVersionUID: This is a unique identifier for each class. It is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.

  • Transient Fields: Fields marked as transient are not serialized. This is useful for fields that do not represent the state of the object or are sensitive (e.g., passwords)- SELECTIVE SERIALISATION

  • Custom Serialization: You can customize the serialization process by implementing writeObject and readObject methods in your class.

Important Points

  1. Exception Handling: Always handle exceptions, particularly IOException, for robust code.

  2. File Path: Use absolute or relative file paths correctly.

  3. Resource Management: Use try-with-resources statement to automatically close file resources.

  4. Character vs Byte Streams: Use FileReader/FileWriter for characters, FileInputStream/FileOutputStream for bytes.

Utilizing try-with-resources

Java 7 introduced the try-with-resources statement, which ensures that each resource is closed at the end of the statement. This simplifies resource management. For example:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileHandlingWithResources {
    public static void main(String[] args) {
        // Writing to a file
        try (FileWriter writer = new FileWriter("example.txt")) {
            writer.write("More content for the example file.\n");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Reading from a file
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}