Why working with files in Java isn't scary?
\n\nEvery developer, even if they only write backend in Java, sooner or later faces the need to save data, read a configuration, or process a log. Working with files and the file system in Java is a fundamental skill that turns "toy" console applications into real utilities. And yes, in 2024 we have not only the good old File, but also the powerful java.nio.file.
In this article, we'll cover everything: from opening a notepad to manipulating access rights. Let's go!
\n\n1. The Classic Approach: java.io.File
\n\nLet's start with the grandfather. The File class appeared in Java 1.0 and is still used. But let's be honest: it's more about metadata than content. With it, you can check if a file exists, create a folder, get a list of files.
import java.io.File;\n\npublic class FileExample {\n public static void main(String[] args) {\n File file = new File("/home/user/docs/notes.txt");\n \n System.out.println("File exists: " + file.exists());\n System.out.println("Absolute path: " + file.getAbsolutePath());\n System.out.println("Size: " + file.length() + " bytes");\n \n // Creating a directory\n File dir = new File("/home/user/new_folder");\n if (dir.mkdir()) {\n System.out.println("Folder created");\n }\n }\n}\n\nDisadvantage: File cannot properly read large files — streams are needed for that. And it doesn't support symbolic links (soft links) out of the box. That's why Sun (and later Oracle) released NIO.
2. Reading Files: From InputStream to BufferedReader
\n\nReading is the most common operation. If the file is text, use BufferedReader — it buffers data and works fast.
import java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\n\npublic class ReadFile {\n public static void main(String[] args) {\n try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {\n String line;\n while ((line = br.readLine()) != null) {\n System.out.println(line);\n }\n } catch (IOException e) {\n System.err.println("Read error: " + e.getMessage());\n }\n }\n}\n\nFor binary files (images, archives) use FileInputStream:
import java.io.FileInputStream;\nimport java.io.IOException;\n\npublic class ReadBinary {\n public static void main(String[] args) {\n try (FileInputStream fis = new FileInputStream("image.png")) {\n byte[] buffer = new byte[1024];\n int bytesRead;\n while ((bytesRead = fis.read(buffer)) != -1) {\n // process buffer[0..bytesRead]\n }\n } catch (IOException e) {\n e.printStackTrace();\n }\n }\n}\n\nImportant: always use try-with-resources — this guarantees the stream is closed, even if an exception is thrown.
3. Writing to a File: BufferedWriter and FileOutputStream
\n\nWriting is almost symmetrical to reading. For text — BufferedWriter, for binary data — FileOutputStream.
import java.io.BufferedWriter;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\npublic class WriteFile {\n public static void main(String[] args) {\n try (BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {\n bw.write("Hello, world!");\n bw.newLine();\n bw.write("Java is powerful.");\n } catch (IOException e) {\n e.printStackTrace();\n }\n }\n}\n\nIf you need to append to the end of the file instead of overwriting it