Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Java File Class and I/O Streams

Tech May 14 1

The File class in Java provides an abstract representation of file and directory pathnames. It is essential for performing file operations like creation, deletion, checking existence, and managing paths.


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

public class FileOperations {
   public static void main(String[] args) {
       // Example of using File class methods

       // Constructing a File object
       // Note: Use File.separator for platform-independent path separation
       File sampleFile = new File("resources" + File.separator + "sample.txt");

       // Obtaining file information
       System.out.println("Absolute Path: " + sampleFile.getAbsolutePath());
       System.out.println("Path: " + sampleFile.getPath());
       System.out.println("File Name: " + sampleFile.getName());
       System.out.println("File Size (bytes): " + sampleFile.length());

       // Checking file properties
       System.out.println("Exists: " + sampleFile.exists());
       System.out.println("Is Directory: " + sampleFile.isDirectory());
       System.out.println("Is File: " + sampleFile.isFile());

       // File creation
       File newFile = new File("resources" + File.separator + "newfile.txt");
       try {
           if (newFile.createNewFile()) {
               System.out.println("File created successfully.");
           } else {
               System.out.println("File already exists or could not be created.");
           }
       } catch (IOException e) {
           System.err.println("Error creating file: " + e.getMessage());
       }

       // Directory creation
       File newDirectory = new File("resources" + File.separator + "newdir");
       if (newDirectory.mkdir()) {
           System.out.println("Directory created successfully.");
       } else {
           System.out.println("Directory already exists or could not be created.");
       }

       // Recursive directory creation
       File nestedDirectories = new File("resources" + File.separator + "level1" + File.separator + "level2");
       if (nestedDirectories.mkdirs()) {
           System.out.println("Nested directories created successfully.");
       } else {
           System.out.println("Nested directories already exist or could not be created.");
       }

       // File/Directory deletion
       File fileToDelete = new File("resources" + File.separator + "newfile.txt");
       if (fileToDelete.delete()) {
           System.out.println("File deleted successfully.");
       } else {
           System.out.println("File could not be deleted.");
       }

       // Listing directory contents
       File directoryToList = new File("resources");
       String[] fileNames = directoryToList.list();
       if (fileNames != null) {
           System.out.println("\nFiles and directories in " + directoryToList.getName() + ":");
           for (String name : fileNames) {
               System.out.println(name);
           }
       }

       File[] files = directoryToList.listFiles();
       if (files != null) {
           System.out.println("\nFile objects in " + directoryToList.getName() + ":");
           for (File file : files) {
               System.out.println(file.getName());
           }
       }
   }
}
       

The FileFilter interface (and lambda expressions) can be used with methods like listFiles() to selectively retreive files or directories based on certain criteria.


import java.io.File;
import java.io.FileFilter;

public class FileFilterExample {

   public static void main(String[] args) {
       File startDirectory = new File("resources");
       processDirectory(startDirectory);
   }

   public static void processDirectory(File directory) {
       if (directory.isDirectory()) {
           // List files and directories that are either directories or end with .png
           File[] filteredFiles = directory.listFiles((dir, name) -> {
               File currentFile = new File(dir, name);
               return currentFile.isDirectory() || name.toLowerCase().endsWith(".png");
           });

           if (filteredFiles != null) {
               for (File file : filteredFiles) {
                   if (file.isDirectory()) {
                       processDirectory(file); // Recurse into subdirectories
                   } else {
                       System.out.println("Found file: " + file.getPath());
                   }
               }
           }
       } else {
           // This part is generally not reached if the initial call is with a directory
           // and the filter only returns directories or files within directories.
           // However, for completeness, if a non-directory is passed and it matches criteria:
           System.out.println("Found file: " + directory.getPath());
       }
   }
}
       

Java's I/O streams are fundamental for reading from and writing to various data sources, including files. Streams are categorized into byte streams (for raw binary data) and character streams (for text data).

Byte Streams

OutputStream and InputStream are abstract classes for byte-oriented operations. Concrete implementations like FileOutputStream and FileInputStream are used for file handling.


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

public class ByteStreamExample {
   public static void main(String[] args) throws IOException {
       String outputPath = "resources" + File.separator + "byte_output.txt";
       String inputPath = "resources" + File.separator + "byte_output.txt";
       String imagePath = "resources" + File.separator + "source.jpg";
       String imageCopyPath = "resources" + File.separator + "copied_source.jpg";

       // Byte Output Stream (writing bytes)
       try (FileOutputStream fos = new FileOutputStream(outputPath, true)) { // 'true' for append mode
           byte[] data = "Hello, Byte Streams!\n".getBytes();
           fos.write(data);
       } catch (IOException e) {
           System.err.println("Error writing to file: " + e.getMessage());
       }

       // Byte Input Stream (reading bytes)
       try (FileInputStream fis = new FileInputStream(inputPath)) {
           byte[] buffer = new byte[1024];
           int bytesRead;
           System.out.println("Reading from byte_output.txt:");
           while ((bytesRead = fis.read(buffer)) != -1) {
               System.out.print(new String(buffer, 0, bytesRead));
           }
       } catch (IOException e) {
           System.err.println("Error reading from file: " + e.getMessage());
       }

       // File Copying using byte streams
       try (FileInputStream sourceImage = new FileInputStream(imagePath);
            FileOutputStream destinationImage = new FileOutputStream(imageCopyPath)) {

           byte[] buffer = new byte[4096]; // Larger buffer for efficiency
           int bytesRead;
           while ((bytesRead = sourceImage.read(buffer)) != -1) {
               destinationImage.write(buffer, 0, bytesRead);
           }
           System.out.println("\nImage copied successfully.");
       } catch (IOException e) {
           System.err.println("Error copying image file: " + e.getMessage());
       }
   }
}
       

Character Streams

Reader and Writer are abstract classes for character-oriented operations. FileReader and FileWriter are common implementations for text files.


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

public class CharacterStreamExample {
   public static void main(String[] args) {
       String charOutputPath = "resources" + File.separator + "char_output.txt";
       String charInputPath = "resources" + File.separator + "char_output.txt";

       // Character Output Stream (writing characters)
       try (FileWriter fw = new FileWriter(charOutputPath, true)) { // 'true' for append mode
           fw.write("This is a line of Chinese characters.\r\n");
           fw.write("Another line for testing.\n");
       } catch (IOException e) {
           System.err.println("Error writing character data: " + e.getMessage());
       }

       // Character Input Stream (reading characters)
       try (FileReader fr = new FileReader(charInputPath)) {
           char[] buffer = new char[1024];
           int charsRead;
           System.out.println("\nReading from char_output.txt:");
           while ((charsRead = fr.read(buffer)) != -1) {
               System.out.print(new String(buffer, 0, charsRead));
           }
       } catch (IOException e) {
           System.err.println("Error reading character data: " + e.getMessage());
       }
   }
}
       

The Properties class is a specialized Hashtable for storing and retrieving configuration settings. It's commonly used for reading and writing key-value pairs from/to text files.


import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class PropertiesExample {
   public static void main(String[] args) throws IOException {
       Properties config = new Properties();
       String propertiesFilePath = "resources" + File.separator + "config.properties";

       // Setting properties
       config.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
       config.setProperty("database.username", "user");
       config.setProperty("database.password", "secret");
       config.setProperty("app.version", "1.0.0");

       // Writing properties to a file
       try (FileWriter writer = new FileWriter(propertiesFilePath)) {
           config.store(writer, "Application Configuration Settings");
           System.out.println("Properties saved to " + propertiesFilePath);
       } catch (IOException e) {
           System.err.println("Error saving properties: " + e.getMessage());
       }

       // Reading properties from a file
       Properties loadedConfig = new Properties();
       try (FileReader reader = new FileReader(propertiesFilePath)) {
           loadedConfig.load(reader);
           System.out.println("\nLoaded Properties:");
           Set<string> propertyNames = loadedConfig.stringPropertyNames();
           for (String key : propertyNames) {
               System.out.println(key + " = " + loadedConfig.getProperty(key));
           }
       } catch (IOException e) {
           System.err.println("Error loading properties: " + e.getMessage());
       }
   }
}
       </string>

Buffered streams enhance performance by reading or writing data in larger chunks, reducing the number of I/O operations. They wrap around other streams.

Buffered Byte Streams


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedByteStreamExample {
   public static void main(String[] args) throws IOException {
       String dataPath = "resources" + File.separator + "buffered_data.bin";

       // Buffered Output Stream
       try (FileOutputStream fos = new FileOutputStream(dataPath);
            BufferedOutputStream bos = new BufferedOutputStream(fos)) {
           
           byte[] dataToWrite = "Writing data with buffering.\n".getBytes();
           bos.write(dataToWrite);
           bos.flush(); // Ensure data is written to the underlying stream
           System.out.println("Buffered byte data written.");
       } catch (IOException e) {
           System.err.println("Error writing buffered byte data: " + e.getMessage());
       }

       // Buffered Input Stream
       try (FileInputStream fis = new FileInputStream(dataPath);
            BufferedInputStream bis = new BufferedInputStream(fis)) {
           
           byte[] buffer = new byte[1024];
           int bytesRead;
           System.out.println("Reading buffered byte data:");
           while ((bytesRead = bis.read(buffer)) != -1) {
               System.out.print(new String(buffer, 0, bytesRead));
           }
       } catch (IOException e) {
           System.err.println("Error reading buffered byte data: " + e.getMessage());
       }
   }
}
       

Buffered Character Streams


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

public class BufferedCharStreamExample {
   public static void main(String[] args) throws IOException {
       String charDataPath = "resources" + File.separator + "buffered_char_data.txt";

       // Buffered Output Stream (Writer)
       try (FileWriter fw = new FileWriter(charDataPath);
            BufferedWriter bw = new BufferedWriter(fw)) {
           
           bw.write("Buffered character line 1.");
           bw.newLine(); // Platform-independent newline
           bw.write("Buffered character line 2.");
           System.out.println("Buffered character data written.");
       } catch (IOException e) {
           System.err.println("Error writing buffered character data: " + e.getMessage());
       }

       // Buffered Input Stream (Reader)
       try (FileReader fr = new FileReader(charDataPath);
            BufferedReader br = new BufferedReader(fr)) {
           
           String line;
           System.out.println("Reading buffered character data:");
           while ((line = br.readLine()) != null) {
               System.out.println(line);
           }
       } catch (IOException e) {
           System.err.println("Error reading buffered character data: " + e.getMessage());
       }
   }
}
       

Conversion streams, like InputStreamReader and OutputStreamWriter, bridge byte streams and character streams. They allow specifying character encodings, which is crucial for handling text data correctly across different platforms.


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public class ConversionStreamExample {
   public static void main(String[] args) throws IOException {
       String gbkFilePath = "resources" + File.separator + "data_gbk.txt";
       String utf8FilePath = "resources" + File.separator + "data_utf8.txt";

       // --- Create a sample GBK encoded file ---
       try (OutputStreamWriter gbkWriter = new OutputStreamWriter(new FileOutputStream(gbkFilePath), "GBK")) {
           gbkWriter.write("这是GBK编码的文本。\n");
           gbkWriter.write("Another line.\n");
       } catch (IOException e) {
           System.err.println("Error creating GBK file: " + e.getMessage());
       }
       // --- End sample file creation ---

       // Converting GBK encoded file to UTF-8 encoded file
       try (InputStreamReader gbkReader = new InputStreamReader(new FileInputStream(gbkFilePath), "GBK");
            OutputStreamWriter utf8Writer = new OutputStreamWriter(new FileOutputStream(utf8FilePath), StandardCharsets.UTF_8)) {
           
           char[] buffer = new char[1024];
           int charsRead;
           while ((charsRead = gbkReader.read(buffer)) != -1) {
               utf8Writer.write(buffer, 0, charsRead);
           }
           System.out.println("File converted from GBK to UTF-8 successfully.");
       } catch (IOException e) {
           System.err.println("Error during file conversion: " + e.getMessage());
       }

       // --- Reading the newly created UTF-8 file ---
       System.out.println("\nReading the UTF-8 file:");
       try (InputStreamReader utf8Reader = new InputStreamReader(new FileInputStream(utf8FilePath), StandardCharsets.UTF_8)) {
           char[] buffer = new char[1024];
           int charsRead;
           while ((charsRead = utf8Reader.read(buffer)) != -1) {
               System.out.print(new String(buffer, 0, charsRead));
           }
       } catch (IOException e) {
           System.err.println("Error reading UTF-8 file: " + e.getMessage());
       }
       // --- End reading ---
   }
}
       

Serialization allows converting an object's state in to a byte stream, which can then be stored in a file or transmitted. ObjectOutputStream writes objects, and ObjectInputStream reads them back.

For an object to be serializable, its class must implement the java.io.Serializable interface. Fields marked as static or transient are not serialized.


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerializableObject implements Serializable {
   // A serialVersionUID is recommended for version control of serialized objects.
   private static final long serialVersionUID = 1L; 

   private String name;
   private Integer age;
   // private transient String sensitiveData; // This field would not be serialized

   public SerializableObject(String name, Integer age) {
       this.name = name;
       this.age = age;
   }

   // Getters and Setters (optional, but good practice)
   public String getName() { return name; }
   public void setName(String name) { this.name = name; }
   public Integer getAge() { return age; }
   public void setAge(Integer age) { this.age = age; }

   @Override
   public String toString() {
       return "SerializableObject{" +
              "name='" + name + '\'' +
              ", age=" + age +
              '}';
   }

   public static void main(String[] args) throws IOException, ClassNotFoundException {
       String objectFilePath = "resources" + File.separator + "data.ser";
       SerializableObject person = new SerializableObject("Alice", 30);

       // Object Serialization (Writing)
       try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(objectFilePath))) {
           oos.writeObject(person);
           System.out.println("Object serialized to " + objectFilePath);
       } catch (IOException e) {
           System.err.println("Error during serialization: " + e.getMessage());
       }

       // Object Deserialization (Reading)
       SerializableObject deserializedPerson = null;
       try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(objectFilePath))) {
           deserializedPerson = (SerializableObject) ois.readObject();
           System.out.println("Object deserialized successfully.");
           System.out.println("Deserialized Object: " + deserializedPerson);
       } catch (IOException | ClassNotFoundException e) {
           System.err.println("Error during deserialization: " + e.getMessage());
       }
   }
}
       

PrintStream provides convenient methods for writing formatted data to various destinations, including files and the console. It can wrap other output streams.


import java.io.FileNotFoundException;
import java.io.PrintStream;

public class PrintStreamExample {
   public static void main(String[] args) {
       String outputFilePath = "resources" + File.separator + "print_output.txt";
       PrintStream originalStdout = System.out; // Save original System.out

       try {
           // Redirect System.out to a file
           PrintStream filePrintStream = new PrintStream(outputFilePath);
           System.setOut(filePrintStream);

           System.out.println("This line will be written to the file.");
           System.out.printf("Formatted output: %d, %s%n", 123, "Example");
           System.err.println("This is an error message (still goes to stderr by default).");

           filePrintStream.close(); // Close the PrintStream
           System.out.println("Print stream operations completed. Check " + outputFilePath);

       } catch (FileNotFoundException e) {
           System.err.println("Error redirecting output: " + e.getMessage());
       } finally {
           // Restore System.out to its original state
           System.setOut(originalStdout);
           System.out.println("System.out has been restored.");
       }
   }
}
       
Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.