IO

Reading from a File

The FileInputStream class is used to read raw bytes from a file. If you're reading character data (like text), it's better to use FileReader.

import java.io.FileInputStream;
import java.io.IOException;

public class ReadFile {
  public static void main(String[] args) {
    try (FileInputStream fis = new FileInputStream("input.txt")) {
      int data;
      while ((data = fis.read()) != -1) {
        System.out.print((char) data);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Writing to a File

The FileOutputStream class is used to write raw bytes to a file. For writing character data, use FileWriter.

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

public class WriteFile {
  public static void main(String[] args) {
    try (FileOutputStream fos = new FileOutputStream("output.txt")) {
      String content = "Hello, World!";
      fos.write(content.getBytes());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Using Buffered Streams

Buffered streams read or write data in large chunks rather than one byte/character at a time. This often leads to faster I/O.

For reading:

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

public class BufferedReadFile {
  public static void main(String[] args) {
    try (BufferedReader br = new BufferedReader(new FileReader("input.txt"))) {
      String line;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

For writing:

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

public class BufferedWriteFile {
  public static void main(String[] args) {
    try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {
      String content = "Hello, World!";
      bw.write(content);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Tips: - Always close your streams after use to free up system resources. Using try-with-resources, as shown in the examples, helps ensure streams are closed automatically. - If you're working with text files and care about character encoding, consider using InputStreamReader and OutputStreamWriter as they allow specifying a charset. - For large files, it's beneficial to use buffered streams as they can improve performance.

Java provides a clear distinction between byte-oriented streams (for binary data) and character-oriented streams (for text data). The Reader and Writer abstract classes in the java.io package form the foundation of character-oriented streams. They handle the encoding and decoding automatically, making text I/O operations more intuitive.

FileReader

Reads text files. It uses the default character encoding unless otherwise specified.

try (FileReader fr = new FileReader("file.txt")) {
  int c;
  while ((c = fr.read()) != -1) {
    System.out.print((char) c);
  }
} catch (IOException e) {
  e.printStackTrace();
}

StringReader

Allows reading from a string as if it were a stream.

String data = "Hello, World!";
try (StringReader sr = new StringReader(data)) {
  int c;
  while ((c = sr.read()) != -1) {
    System.out.print((char) c);
  }
} catch (IOException e) {
  e.printStackTrace();
}

BufferedReader

Reads text from a character input stream, buffering characters to provide efficient reading of characters, arrays, and lines.

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
  String line;
  while ((line = br.readLine()) != null) {
    System.out.println(line);
  }
} catch (IOException e) {
  e.printStackTrace();
}

FileWriter

Writes to text files. It uses the default character encoding unless otherwise specified.

try (FileWriter fw = new FileWriter("file.txt")) {
  fw.write("Hello, World!");
} catch (IOException e) {
  e.printStackTrace();
}

StringWriter

Allows writing to a string as if it were a stream.

try (StringWriter sw = new StringWriter()) {
  sw.write("Hello, World!");
  System.out.println(sw.toString());
} catch (IOException e) {
  e.printStackTrace();
}

BufferedWriter

Writes text to a character output stream, buffering characters to provide efficient writing of single characters, arrays, and strings.

try (BufferedWriter bw = new BufferedWriter(new FileWriter("file.txt"))) {
  bw.write("Hello, World!");
} catch (IOException e) {
  e.printStackTrace();
}

Best Practices

Path

The Path interface represents a file or directory's location in the file system. You can obtain a Path instance using the Paths utility class.

import java.nio.file.Path;
import java.nio.file.Paths;

public class PathExample {
  public static void main(String[] args) {
    Path path = Paths.get("path/to/file.txt");
    System.out.println(path);
  }
}

Files

The Files class provides a suite of methods to manipulate files and directories.

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.List;

public class ReadFile {
  public static void main(String[] args) {
    Path path = Paths.get("path/to/file.txt");
    try {
      List<String> lines = Files.readAllLines(path);
      for (String line : lines) {
        System.out.println(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Write to a file:

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class WriteFile {
  public static void main(String[] args) {
    Path path = Paths.get("path/to/file.txt");
    List<String> content = Arrays.asList("Hello", "World!");

    try {
      Files.write(path, content);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

useful methods:

Advantages of the java.nio.file API:

Exercises

Basic File Read and Write

Task: Write a program that reads content from an input file and writes it to an output file.

Read from input.txt Write to output.txt

Uppercase Converter

Task: Read a file, convert all its contents to uppercase, and then write the result to another file.

Read from lowercase.txt Convert the content to uppercase Write the converted content to uppercase.txt

Word Counter

Task: Read a file and count the number of words in it. Print the count to the console.

Line Reverser

Task: Read a text file and write its content to another file such that the order of lines in the output file is the reverse of the input file.

Binary File Copy

Task: Copy a binary file (e.g., an image or audio file) using FileInputStream and FileOutputStream.

Read from source.jpg Write to destination.jpg

Buffered Read and Write

Task: Use BufferedReader and BufferedWriter to read a file and write its content to another file.

Filter Words

Task: Read a text file and write only the words longer than 5 characters to another file.

Replace Word

Task: Read a file, replace every occurrence of the word "Java" with "Python", and write the result to another file.

Merge Multiple Files

Task: Merge the content of multiple text files into a single file.

Read from file1.txt, file2.txt, and file3.txt Write merged content to merged.txt

Count Occurrences

Task: Read a file and count the number of occurrences of a specific word (case-insensitive).

Tip: Use a function and pass the word as an argument to make it reusable.

Solutions

Basic File Read and Write

import java.io.*;

public class BasicReadWrite {
  public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("input.txt");
    FileWriter fw = new FileWriter("output.txt");

    int c;
    while ((c = fr.read()) != -1) {
      fw.write(c);
    }

    fr.close();
    fw.close();
  }
}

Uppercase Converter

public class UppercaseConverter {
  public static void main(String[] args) throws IOException {
    FileReader fr = new FileReader("lowercase.txt");
    FileWriter fw = new FileWriter("uppercase.txt");

    int c;
    while ((c = fr.read()) != -1) {
      fw.write(Character.toUpperCase(c));
    }

    fr.close();
    fw.close();
  }
}

Word Counter

public class WordCounter {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("input.txt"));
    String line;
    int wordCount = 0;

    while ((line = br.readLine()) != null) {
      wordCount += line.split("\\s+").length;
    }

    System.out.println("Word count: " + wordCount);
    br.close();
  }
}

Line Reverser

import java.util.*;

public class LineReverser {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("input.txt"));
    List<String> lines = new ArrayList<>();
    String line;

    while ((line = br.readLine()) != null) {
      lines.add(line);
    }

    Collections.reverse(lines);
    BufferedWriter bw = new BufferedWriter(new FileWriter("reversed.txt"));

    for (String l : lines) {
      bw.write(l);
      bw.newLine();
    }

    br.close();
    bw.close();
  }
}

Binary File Copy

public class BinaryFileCopy {
  public static void main(String[] args) throws IOException {
    FileInputStream fis = new FileInputStream("source.jpg");
    FileOutputStream fos = new FileOutputStream("destination.jpg");

    int b;
    while ((b = fis.read()) != -1) {
      fos.write(b);
    }

    fis.close();
    fos.close();
  }
}

Buffered Read and Write

(Quite similar to Basic File Read and Write but uses buffered streams for efficiency)

public class BufferedReadWrite {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("input.txt"));
    BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));

    String line;
    while ((line = br.readLine()) != null) {
      bw.write(line);
      bw.newLine();
    }

    br.close();
    bw.close();
  }
}

Filter Words

public class FilterWords {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("input.txt"));
    BufferedWriter bw = new BufferedWriter(new FileWriter("filtered.txt"));

    String line;
    while ((line = br.readLine()) != null) {
      for (String word : line.split("\\s+")) {
        if (word.length() > 5) {
          bw.write(word);
          bw.newLine();
        }
      }
    }

    br.close();
    bw.close();
  }
}

Replace Word

public class ReplaceWord {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader("input.txt"));
    BufferedWriter bw = new BufferedWriter(new FileWriter("replaced.txt"));

    String line;
    while ((line = br.readLine()) != null) {
      bw.write(line.replace("Java", "Python"));
      bw.newLine();
    }

    br.close();
    bw.close();
  }
}

Merge Multiple Files

   public class MergeFiles {
  public static void main(String[] args) throws IOException {
    String[] fileNames = {"file1.txt", "file2.txt", "file3.txt"};
    BufferedWriter bw = new BufferedWriter(new FileWriter("merged.txt"));

    for (String fileName : fileNames) {
      BufferedReader br = new BufferedReader(new FileReader(fileName));
      String line;
      while ((line = br.readLine()) != null) {
        bw.write(line);
        bw.newLine();
      }
      br.close();
    }

    bw.close();
  }
}

Count Occurrences

public class CountOccurrences {
  public static void main(String[] args) throws IOException {
    System.out.println(countWord("input.txt", "Java"));
  }

  public static int countWord(String fileName, String word) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(fileName));
    String line;
    int count = 0;

    while ((line = br.readLine()) != null) {
      for (String w : line.split("\\s+")) {
        if (w.equalsIgnoreCase(word)) {
          count++;
        }
      }
    }

    br.close();
    return count;
  }
}