Java › I/O & NIO

How would you correctly handle character encoding when reading a text file whose encoding isn't known in advance (or might not be UTF-8), and what pitfalls exist with relying on the JVM's platform default charset?

Advanced

Answer

Relying on the platform default charset (via a Reader/Writer constructor overload that doesn't explicitly specify one, like the older new FileReader(path) constructor) is a well-known cross-platform portability pitfall, since the default charset varies by operating system and locale configuration (historically Windows commonly defaulted to a different charset than Linux/macOS), meaning identical code could silently produce different, incorrect results when run on different machines -- as of Java 18, the JVM's default charset changed to always be UTF-8 regardless of platform (a significant, deliberate compatibility-improving change, JEP 400), but explicitly specifying the charset in every I/O call remains strongly recommended best practice regardless, both as defensive coding style and for genuine clarity about the actual expected encoding of the specific file being read.
// Risky (pre-Java 18): relies on platform default, which varies!
Reader reader1 = new FileReader("data.txt");  // encoding depends on the running JVM's platform default

// Always correct and explicit, regardless of JVM version or platform
Reader reader2 = new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8);

// NIO.2 equivalent, also explicit
List<String> lines = Files.readAllLines(Path.of("data.txt"), StandardCharsets.UTF_8);
Real-world example A cross-platform application that worked correctly on the development team's Linux machines produced garbled text output when deployed to a Windows server prior to Java 18, traced to code relying on the platform default charset (which differed between the two operating systems), fixed by explicitly specifying UTF-8 in every file I/O call throughout the codebase.

Common follow-ups: What changed specifically in JEP 400 (Java 18) regarding the default charset, and does it fully eliminate the need to specify charsets explicitly?;How would you detect or guess a file's actual encoding if it genuinely isn't known or documented in advance?