File Handling in Java
Because streams are abstractions that either produce (input stream) or consume (output stream) information, they constitute the foundation of Java’s I/O system. Through the Java I/O system, these streams are connected to actual devices and exhibit uniform behaviour across all devices. Two primary I/O stream types are supported by Java: character streams for 16-bit Unicode characters (optimised for internationalisation) and byte streams for 8-bit bytes (helpful for binary data).
The Class
When working with files and the file system directly instead of through streams, the java.io.File
class is essential. The features of a file or directory itself are described by a File
object, which lets you access or change data like permissions, time, date, and directory paths without dictating how data is read or written.
You can use a variety of constructors to build File
objects, including one that requires a pathname string. The File
class’s primary methods are as follows:
getName()
: Returns the name of the file or directory.getPath()
: Converts the abstract pathname into a string.getAbsolutePath()
: Returns the absolute pathname string.getParent()
: Returns the parent directory’s pathname string.exists()
: Tests whether the file or directory exists.canRead()
/canWrite()
: Checks if the application can read or modify the file.isDirectory()
/isFile()
: Tests if the pathname denotes a directory or a normal file, respectively.length()
: Returns the length of the file in bytes.
For more modern file system operations, especially from JDK 7 onwards, the Path
interface and Files
class in the java.nio.file
package offer a powerful alternative to the File
class. The File
class includes a toPath()
method to convert a File
object into a Path
object, bridging the older and newer APIs.
Creating a File
There are multiple methods for programmatically creating a new, empty file:
- File.createNewFile(): Atomically creates a new, empty file if one with the same name doesn’t already exist.
- FileOutputStream: Creating a
FileOutputStream
object will create the file if it doesn’t exist before opening it for output. - FileWriter: Similar to
FileOutputStream
, creating aFileWriter
object will create the file if it doesn’t exist. - Files.createFile(Path) (NIO.2): This static method creates a new, empty file.
Here’s an example using FileWriter
to create a new file:
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class CreateFileDemo {
public static void main(String[] args) {
String fileName = "myNewFile.txt";
try {
File file = new File(fileName);
// FileWriter will create the file if it doesn't exist
FileWriter writer = new FileWriter(file);
System.out.println("File created successfully: " + file.getAbsolutePath());
writer.close(); // Close the writer even if nothing is written
} catch (IOException e) {
System.err.println("Error creating file: " + e.getMessage());
}
}
}
Code Output:
File created successfully: /path/to/your/project/myNewFile.txt
(The exact path will vary based on your system.)
Writing to File
In order to write data to a file, you usually use Writer
subclasses for characters or OutputStream
subclasses for bytes.
- Byte Streams: To write 8-bit bytes to a file, utilise the
FileOutputStream
. Instead of writing an array of bytes, thewrite(byte[] buffer)
function writes a single byte. - Character Streams: It is possible to write character streams to a file using
FileWriter
. It offerswrite(char[] cbuf)
for character arrays,write(int c)
for single characters, andwrite(String str)
for strings among other functions. - Buffered Streams:
BufferedWriter
has been utilised to wrap aFileWriter
for efficiency. It minimises the quantity of physical writes to the device by buffering the output.
Using the close()
method to end an output stream or writer is essential for freeing up system resources and guaranteeing that any buffered data is sent to the physical device. If you don’t, you risk data loss or “memory leaks”
Even in the event of an exception, streams are immediately terminated when the try
block is exited thanks to the try-with-resources
statement, which has been an automated resource management tool since JDK 7.
Here’s an example of writing to a file using FileWriter
wrapped in a BufferedWriter
with try-with-resources
:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class WriteFileDemo {
public static void main(String[] args) {
String fileName = "output.txt";
String content = "Hello, world!\nThis is a test line.\nAnother line of text.";
// Use try-with-resources to ensure the writer is closed automatically
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
writer.write(content);
System.out.println("Content successfully written to " + fileName);
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
}
}
}
Code Output:
Content successfully written to output.txt
(A file named output.txt
will be created in the current directory with the specified content.)
You can also specify an append
mode in the FileWriter
constructor (e.g., new FileWriter(fileName, true)
) to add content to the end of an existing file rather than overwriting it.
Reading Files
Reader
subclasses for characters and InputStream
subclasses for bytes are commonly used to read data from a file.
- Byte Streams: In order to read 8-bit bytes from a file,
FileInputStream
is utilised. Theread(byte[] buffer)
method reads bytes into an array, while theread()
method reads a single byte (returning -1 at end-of-file). - Character Streams: Character streams can be read from a file using
FileReader
. It has the sameread()
andread(char[] cbuf)
methods asFileInputStream
. - Buffered Readers:
BufferedReaders
are frequently used to surround aFileReader
orInputStreamReader
in order to increase performance and provide access toreadLine()
, which reads a line of text. - Scanner Class: The
java.util.Scanner
class provides a convenient way to read formatted input (e.g., line by line, word by word, or specific data types) from files.
Closing readers and input streams is essential to freeing up resources, much like when writing. Additionally, the try-with-resources
declaration is strongly advised in this case.
Here’s an example of reading from a file using FileReader
wrapped in a BufferedReader
with try-with-resources
:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFileDemo {
public static void main(String[] args) {
String fileName = "output.txt"; // Assuming output.txt exists from previous example
// Use try-with-resources to ensure the reader is closed automatically
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
System.out.println("Reading content from " + fileName + ":");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("Error reading from file: " + e.getMessage());
}
}
}
Code Output:
Reading content from output.txt:
Hello, world!
This is a test line.
Another line of text.
Deleting Files
There are ways to remove files or empty directories using the File
class:
- File.delete(): This function removes the directory or file that the abstract pathname represents. If it is a directory, it cannot be removed until it is empty.
- File.deleteOnExit(): In the event that the Java Virtual Machine ends,
File.deleteOnExit()
requests that the file or directory be erased. - Files.deleteIfExists(Path) (NIO.2): A more reliable method of deleting files or directories that won’t raise an error if the file doesn’t exist.
import java.io.File;
import java.io.IOException;
public class DeleteFileDemo {
public static void main(String[] args) {
String fileName = "myNewFile.txt"; // Assuming myNewFile.txt exists
File fileToDelete = new File(fileName);
if (fileToDelete.exists()) {
if (fileToDelete.delete()) {
System.out.println(fileName + " deleted successfully.");
} else {
System.err.println("Failed to delete " + fileName);
}
} else {
System.out.println(fileName + " does not exist.");
}
}
}
Code Output (if myNewFile.txt exists):
myNewFile.txt deleted successfully.
Code Output (if myNewFile.txt does not exist):
myNewFile.txt does not exist.
Directories
Directories are treated as a unique kind of File
object in Java, which can hold a list of additional files and directories.
- Creating Directories:
- File.mkdir(): One directory is created by using
File.mkdir()
. It returnstrue
if the directory is successful andfalse
if it cannot be formed (for example, if parent directories are absent) or if the directory already exists. - File.mkdirs(): Constructs the directory with the abstract pathname, encompassing any parent directories that are required but no longer exist. Making nested directory structures is much easier using this.
- File.mkdir(): One directory is created by using
- Listing Directories:
- File.list(): The function File.list() yields a string array containing the names of the files and directories within the directory.
- File.list(FilenameFilter filter): Provides a list of strings that meet a given filter request.
- Files.newDirectoryStream(Path) (NIO.2): This function opens a directory and returns a
DirectoryStream
, on which the contents can be iterated.
Here’s an example demonstrating creating and listing directories:
import java.io.File;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class DirectoryDemo {
public static void main(String[] args) {
String parentDirName = "myParentDir";
String nestedDirName = "myParentDir/nestedDir";
File parentDir = new File(parentDirName);
File nestedDir = new File(nestedDirName);
// 1. Create directories
if (parentDir.mkdir()) {
System.out.println("Parent directory '" + parentDirName + "' created.");
} else {
System.out.println("Parent directory '" + parentDirName + "' already exists or failed to create.");
}
if (nestedDir.mkdirs()) { // Using mkdirs to create parent and nested
System.out.println("Nested directory '" + nestedDirName + "' created.");
} else {
System.out.println("Nested directory '" + nestedDirName + "' already exists or failed to create.");
}
// 2. Listing contents of parentDir using File.list()
System.out.println("\nContents of '" + parentDirName + "':");
String[] contents = parentDir.list();
if (contents != null) {
for (String item : contents) {
File itemPath = new File(parentDir, item);
System.out.println(item + (itemPath.isDirectory() ? " (Directory)" : " (File)"));
}
} else {
System.out.println("Could not list contents of '" + parentDirName + "'.");
}
// 3. Listing contents using NIO.2 DirectoryStream
Path dirPath = Paths.get(parentDirName);
System.out.println("\nContents of '" + parentDirName + "' (NIO.2):");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dirPath)) {
for (Path entry : stream) {
System.out.println(entry.getFileName() + (Files.isDirectory(entry) ? " (Directory)" : " (File)"));
}
} catch (IOException e) {
System.err.println("Error listing directory (NIO.2): " + e.getMessage());
}
// Clean up: delete directories (must be empty first for File.delete())
System.out.println("\nCleaning up directories...");
if (nestedDir.delete()) {
System.out.println("Nested directory '" + nestedDirName + "' deleted.");
} else {
System.err.println("Failed to delete nested directory '" + nestedDirName + "'.");
}
if (parentDir.delete()) {
System.out.println("Parent directory '" + parentDirName + "' deleted.");
} else {
System.err.println("Failed to delete parent directory '" + parentDirName + "'.");
}
}
}
Code Output:
Parent directory 'myParentDir' created.
Nested directory 'myParentDir/nestedDir' created.
Contents of 'myParentDir':
nestedDir (Directory)
Contents of 'myParentDir' (NIO.2):
nestedDir (Directory)
Cleaning up directories...
Nested directory 'myParentDir/nestedDir' deleted.
Parent directory 'myParentDir' deleted.
Java provides comprehensive support for file handling and I/O (Input/Output) operations, which are crucial for programs to interact with external data like disk files. The primary packages involved in Java’s I/O system are java.io
and java.nio.file
.