The code of the HappyCoders.eu article series on files in Java – one package per article. Every class with a main() method is one chapter of its article and prints the outputs shown there.
| Article | Package |
|---|---|
| Java BufferedReader (English, German) | eu.happycoders.bufferedreader |
| Java PrintWriter (English, German) | eu.happycoders.printwriter |
| Java FileReader (not yet published; German) | eu.happycoders.filereader |
| Java FileWriter (not yet published; German) | eu.happycoders.filewriter |
| Serialization in Java (English, German) | eu.happycoders.serialization |
| Creating, copying, moving, and deleting files and directories (not yet published; German, English) | eu.happycoders.files |
| Listing directory contents (not yet published; German, English) | eu.happycoders.listing |
The examples use Java 25 language features and need Java 25 or newer. Build once with mvn compile, then run a class from the repository root:
java -cp target/classes eu.happycoders.<package>.<ClassName>
Files the examples create go into target/; the serialization examples write their .ser files into the current directory.
Most examples read the small log file files/server.log.
Intro– reads the log file line by lineCh1Creating–Files.newBufferedReader(),FileReader,InputStreamReaderaround aGZIPInputStream, an own buffer size, and a Latin-1 file read as UTF-8Ch2ReadLine– line terminators, empty lines, and the end of the inputCh3Lines–lines()withfilter()andgroupingBy(), anUncheckedIOExceptionwhile streaming, andFiles.lines()Ch4ReadAll–readAllLines()andreadAllAsString()(Java 25), also after areadLine()Ch5Characters–read()andread(char[], int, int)Ch6MarkReset– an optional header line withmark()andreset(), andskip()Ch6Ready–ready()returnsfalse, yet the nextreadLine()returns a lineCh7Console– reading lines fromSystem.inwith the charset fromstdin.encoding(Java 25)Ch7Readln–IO.readln()(Java 25)Ch8Scanner– tokens withScannerand withsplit(), and how both classes report anIOExceptionCh9Closing– closing theBufferedReadercloses the reader inside itCh10Mistakes– callingreadLine()twice per loop iteration
Most examples write the small log file target/server.log, the file the BufferedReader examples read.
Intro– writes the log file withprintf()Ch1Creating–new PrintWriter(String)with and without a charset, aPrintWriteraroundFiles.newBufferedWriter(), and one around aGZIPOutputStreamCh1WriteCalls– counts the write calls that arrive below aPrintWriter, with and without aBufferedWriterin betweenCh1Append– appending to a file:APPENDalone,CREATEandAPPEND, and aFileWriterwithappend = trueCh2Print–print()andprintln()for different types andnull, the line separator,write(int)vs.print(int), andappend()Ch3Printf– format strings, the locale, chainedprintf()calls, and a missing argumentCh4Flush– when the bytes reach the file, with and without autoFlushCh5CheckError– a failing writer, writing afterclose(), and the euro sign in ISO-8859-1Ch6Closing– closing thePrintWritercloses the writer inside it, and what closing aPrintWriteraroundSystem.outdoesCh7StringWriter– text and a stack trace into a string, and the same withformatted()andStringBuilderCh8Console– aPrintWriteraroundSystem.outandSystem.console().writer()Ch9PrintStream– how often aPrintStreamand aPrintWriter, both with autoFlush, flush their streamCh10Mistakes– aPrintWriterthat is never closed leaves the file empty
Most examples read the small log file files/server.log.
Intro– reads the log file withreadAllAsString()(Java 25)Ch1Creating– aFileReaderfrom a file name, aFile, and aPath,getEncoding()for different charsets, and files that cannot be openedCh2Read–read()character by character, and an emoji arriving as two halves of a surrogate pairCh2ReadArray–read(char[])in blocks, and what is left in the array after the last blockCh2ReadAll–readAllLines()andreadAllAsString()(Java 25), also afterskip()Ch2TransferTo– re-encoding a file from ISO-8859-1 to UTF-8 withtransferTo()Ch2Unsupported–mark()andreset()are not supportedCh3Replacement– a Latin-1 file read as UTF-8: replacement characters from aFileReader, aMalformedInputExceptionfrom anInputStreamReaderwith a reporting decoderCh3Bom– a UTF-8 byte order mark arrives as the first characterCh4InputStreamReader– a classpath resource read with anInputStreamReader, and an unknown charset nameCh5BufferedReader– aBufferedReaderaround aFileReaderCh6Binary– a binary file read with aFileReaderand with aFileInputStreamCh8Closing– reading afterclose(), and open file descriptors ofFileReaders that are never closed (Linux and macOS)
Most examples write lines of the log file files/server.log into target/server.log.
Intro– writes two log linesCh1Creating– aFileWriterfrom a file name, aFile, and aPath, overwriting and appending, appending to a file that does not exist,getEncoding(), and files that cannot be createdCh2Write–write(int)with the two halves of a surrogate pair, with a number, and with a code point;write(String)andappend(), also withnullCh2Flush– when the bytes reach the file:flush(), many short writes through the 512-byte buffer, and one long write that grows it to 8,192 bytesCh3Unmappable– the euro sign in ISO-8859-1: a question mark from aFileWriter, anUnmappableCharacterExceptionfrom anOutputStreamWriterwith a reporting encoder, fromFiles.newBufferedWriter(), and fromFiles.writeString(); half a surrogate pair at the end of a stringCh4OutputStreamWriter– anOutputStreamWriteraround aGZIPOutputStream, and an unknown charset nameCh5BufferedWriter– aBufferedWriteraround aFileWriterCh6Binary– all 256 byte values written with aFileWriterand with aFileOutputStreamCh8Closing– aFileWriterthat is never closed leaves the file empty, also after a garbage collection; writing afterclose()
The examples work on a small order model: the classes Order and Customer and the record OrderItem. Chapters that need a variant of a class – one that is not serializable, has no serialVersionUID, or validates in readObject() – keep it in a package of its own (graph, transients, versioning, inheritance, custom, special, filter).
Intro– writes an order into a file and reads it backCh1Writing–ObjectOutputStream: writing into a byte array, the first bytes of the stream, bufferingCh2Reading–ObjectInputStream: pattern matching on the result, several objects in one stream, buffering, a file that is not a serialization streamCh3ObjectGraph–NotSerializableException, shared references, the same object written twice,reset()andwriteUnshared()Ch4Transient–transientfields after deserialization and howreadObject()restores themCh5Versioning– the computedserialVersionUIDand what happens when a class changes between writing and readingCh5Misdeclaration– a misdeclaredserialVersionUID, for the JFR eventjdk.SerializationMisdeclaration(the command is in the class comment)Ch6Inheritance– a serializable class with a non-serializable superclassCh7Custom– validation inreadObject(),writeObject()for the superclass state,readResolve(), the serialization proxyCh8Special– records, enums (including a renamed constant), lambdas, and inner classesCh8LambdaNames– a serializable lambda written withwriteand read withread; renaming its variable and recompiling makes the old stream unreadable (the steps are in the class comment)Ch9Collections–ArrayListcapacity,List.of(), views such askeySet()andsubList()Ch10Filters– deserialization filters from patterns, the missing!*, and the limitsmaxdepth(against Joshua Bloch’s deserialization bomb) andmaxarrayCh10FilterFactory– a filter factory that applies a filter within aScopedValuescopeCh10GlobalFilter– a JVM-wide filter with-Djdk.serialFilter(the command is in the class comment; add-Djava.util.logging.config.file=serialfilter-logging.propertiesto log rejected classes)Ch11Size– the size of an order withObjectOutputStreamand withDataOutputStream
The class PackageSwitchingObjectInputStream in eu.happycoders.serialization.util reads a stream written by one version of a class with another version of it: the chapters keep both versions side by side, e.g. versioning.explicit.v1.Customer and versioning.explicit.v2.Customer. Serialization compares class names without their package, so this simulates a class that changed between writing and reading.
Every example starts with a fresh directory target/logs/ that holds a copy of files/server.log. Examples.reset() creates that directory, and Examples.printTree() prints what is in it after an operation. The outputs of the article's run are in results/files/outputs-jdk25.txt. Ch2Exists, Ch3CreateFile, and Ch5TempFiles set or read POSIX permissions and run on Linux and macOS only.
Intro– rotates the log file: create the directory, move the old log aside, create a new oneCh1FilesVsFile–File.renameTo()andFile.delete()returnfalse,Files.move()andFiles.delete()say whyCh2Exists–exists(),notExists(),isRegularFile(),isDirectory(), a dangling symbolic link, and a directory in which existence cannot be determinedCh2ExistsRace– two threads check whether a file exists and create it if not, 10,000 times: how often the check was already outdatedCh3CreateFile–createFile(), its exceptions, create-if-not-exists,writeString()withCREATE_NEW, POSIX permissions,File.createNewFile()Ch4CreateDirectory–createDirectory()vs.createDirectories(), their exceptions,File.mkdir()andmkdirs()Ch5TempFiles–createTempFile(),createTempDirectory(), their permissions, cleaning up with try/finallyCh6Copy–copy()into a directory, onto an existing file, withCOPY_ATTRIBUTESandNOFOLLOW_LINKS, from anInputStream, to anOutputStream, andmismatch()Ch7CopyDirectory–copy()on a directory creates only an empty one;copyDirectory()withwalkFileTree()Ch8Move–move()into a directory, renaming withresolveSibling(), moving a directory,REPLACE_EXISTING, and writing to a temp file followed byATOMIC_MOVECh9Delete–delete(),deleteIfExists(),DirectoryNotEmptyException, deleting a symbolic link,File.delete()Ch10DeleteDirectory–deleteDirectory()withwalkFileTree()and withwalk(), and a missing directoryCh11Links–createSymbolicLink(),readSymbolicLink(),createLink(), and what survives deleting the original
The examples list the directory files/project/, a small Maven project with five files in three subdirectories. Directories that some examples create themselves end up under target/.
Intro–Files.list()on the project directoryCh1List–list()is not recursive, the order is the file system's,sorted(), filtering for directories,NotDirectoryExceptionandNoSuchFileExceptionCh1DirectoryStream–newDirectoryStream()with the globs*.mdand*.{md,xml}Ch1OpenStreams– opens streams without closing them until the process runs out of file handlesCh2ListRecursive– finding.javafiles withlist()and recursion written by handCh3Walk–walk(), its depth-first order,maxDepth1 and 0,FOLLOW_LINKS, and aFileSystemLoopExceptionCh4WalkFileTree–walkFileTree()with aSimpleFileVisitor, aLoggingVisitorthat numbers every call,SKIP_SUBTREE, andTERMINATECh5Find–find()by file name, by size, and withmaxDepth1Ch6PathMatcher–glob:**/*.java, a glob on the file name only, and aregex:matcherCh7AccessDenied– howwalk(),find(),walkFileTree()with and withoutvisitFileFailed(), andlist()with recursion react to a directory without read permission; sets POSIX permissions and runs on Linux and macOS onlyCh8LegacyFile–File.list()andFile.listFiles(), which returnnullfor a missing directory
The outputs of the article's run are in results/listing/outputs-jdk25.txt.
Each article's JMH benchmarks are in the benchmark subpackage of its package:
ReadBenchmark– reading a 100,000,000-byte UTF-8 text file withInputStreamReader,FileReader, andBufferedReader(read(),read(char[]),readLine(),lines(),readAllLines()), and withScanner.nextLine()BufferSizeBenchmark–readLine()with buffer sizes from 256 to 1,048,576 charactersReadCallCounter– not JMH: counts how often theInputStreamReaderreads from the file when aBufferedReaderreads it line by line, for buffer sizes from 256 to 1,048,576 characters; the count is the same for every sizeDecoderWarmupCheck– not JMH: decodes the test file with anInputStreamReaderin blocks of one size after warming the JVM up with another, one JVM per call; it shows that the speed depends on the warm-up block size, not on the measured one (the command is in the class comment)WriteBenchmark– writing 1,222,747 lines, 100,000,000 bytes of UTF-8 text, withBufferedWriter, with aPrintWriteraroundFiles.newBufferedWriter(), around a file name, and around aFileWriter, with autoFlush, and with aPrintStream; the lines are those of the test file thatReadBenchmarkreadsFormatBenchmark– writing 1,000,000 log lines withprintf(), withprintln()and string concatenation, and with oneprint()call per field, with and without aBufferedWriterbelow thePrintWriterWriteCallCounter– not JMH: counts the write calls that arrive at theOutputStreamWriterand at theOutputStreambelow it when aPrintWriterwrites the test lines, with and without aBufferedWriterand with autoFlushfilewriter.benchmark.WriteBenchmark– writing the same 1,222,747 lines with aFileWritercharacter by character, line by line, and in blocks of 8,192 characters, and with aBufferedWriteraround theFileWritercharacter by character, line by line, and line by line with aflush()after every lineCopyBenchmark– copies a file of 100,000,000 bytes withFiles.copy(), withFiles.copy()andCOPY_ATTRIBUTES(a clone on APFS since Java 20), withInputStream.transferTo(), withFileChannel.transferTo(), and with a loop that copies through an 8,192-byte buffer from aFileInputStreamto aFileOutputStream; the teardown forces each copy to disk before deleting itCloneSizeCheck– not JMH: clones files of 1,000,000, 100,000,000, and 1,000,000,000 bytes withFiles.copy()andCOPY_ATTRIBUTESand prints the median time per size; on APFS it does not depend on the size
mvn package builds target/benchmarks.jar with all of them. Run the benchmarks of one article with its package as filter – a bare class name like ReadBenchmark can match more than you expect:
mvn package
java -jar target/benchmarks.jar eu.happycoders.bufferedreader.benchmark
java -jar target/benchmarks.jar eu.happycoders.printwriter.benchmark
java -jar target/benchmarks.jar eu.happycoders.filewriter.benchmark
java -jar target/benchmarks.jar eu.happycoders.files.benchmark
The BufferedReader and PrintWriter runs take about 15 minutes each, the FileWriter run about ten minutes, the copy benchmark about five minutes. Close other applications while they run. The results of the articles' runs are in results/<package>/, e.g. results/printwriter/apple-m5-pro/.
Stay up-to-date with the latest Java features with this free PDF Cheat Sheet!
- Avoid lengthy research with this concise overview of all Java versions from Java 10 to Java 27.
- Discover the innovative features of each new Java version, summarized on a single page.
- Impress your team with your up-to-date knowledge of the latest Java version.
👉 Download the free Java Versions PDF
(Hier geht's zur deutschen Version → Java-Versionen PDF)
With this free 1-page PDF cheat sheet, you'll always have the 7 most important complexity classes at a glance.
- Always choose the most efficient data structures and thus increase the performance of your applications.
- Be prepared for technical interviews and confidently present your algorithm knowledge.
- Become a sought-after problem solver and be known for systematically tackling complex problems.
👉 Download the free Big O Cheat Sheet
(Hier geht's zur deutschen Version → O-Notation Cheat Sheet)
👉 Want to stay on top of modern Java? Sign up for the HappyCoders newsletter – Modern Java: new versions & features, performance, and JVM insights – once a month.
(Hier geht's zur deutschen Version → HappyCoders-Newsletter deutsch)
🇩🇪 An alle Java-Entwickler:innen, die durch fundierte Kenntnisse über Datenstrukturen besseren Code schreiben wollen
Trage dich jetzt unverbindlich auf die Warteliste von „Mastering Data Structures in Java“ ein, und erhalte das beste Angebot!


