Senior 4 min · March 05, 2026

Java Scanner Unclosed Stream — Too Many Open Files Error

Unclosed Scanner exhausts file descriptors after ~1020 files, causing 'Too many open files' error.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Java I/O is how programs read input and write output using streams.
  • The main output tools are System.out.print, println, and printf.
  • Input is handled by Scanner (for user input) or BufferedReader (for speed).
  • Performance insight: BufferedReader is ~3x faster than Scanner for bulk reads because it buffers large chunks.
  • Production insight: Unclosed Scanner objects leak file handles — always close or use try-with-resources.
  • Biggest mistake: Mixing nextInt() with nextLine() without flushing the leftover newline.
Plain-English First

Think of your Java program as a chef in a kitchen. Input is the customer's order — information coming IN to the chef so they know what to cook. Output is the finished meal placed on the table — information going OUT from the chef back to the customer. Just like a restaurant needs a system for taking orders and serving food, Java needs a system for reading data and printing results. That system is what Input and Output (I/O) is all about.

Every useful program in the world does at least one of two things: it takes information in, or it sends information out. Your phone's calculator takes in numbers you tap and outputs an answer. A login screen takes in your password and outputs either a welcome screen or an error. Without input and output, a program just runs silently in a box and does nothing anyone can see. That's why I/O is the very first real-world skill you need as a Java developer — it's how your program talks to the outside world.

Printing to the Console — Java's Built-In Megaphone

Before your program can accept input, it needs to be able to speak. Printing to the console is Java's way of shouting a message to whoever is running the program. Think of it like a scoreboard at a sports game — it's how the program announces what's happening.

Java gives you three closely related tools for this, and beginners often use them interchangeably without understanding the differences. System.out.println() prints your message and then moves the cursor to a new line — like pressing Enter after typing. System.out.print() prints your message but stays on the same line, so the next thing printed appears right next to it. System.out.printf() is the most powerful — it lets you format your output precisely, like lining up numbers in a table.

System is a built-in Java class that represents your computer's environment. out is the output stream attached to your console. And println, print, and printf are the methods you call on it. You don't need to import anything — Java includes System automatically in every program.

PrintingExamples.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class PrintingExamples {
    public static void main(String[] args) {

        // println adds a newline after printing — cursor moves to the next line
        System.out.println("Welcome to TheCodeForge!");

        // print does NOT add a newline — the next output continues on the same line
        System.out.print("First name: ");
        System.out.print("Ada ");
        System.out.print("Lovelace");

        // We need a manual newline here to move to the next line
        System.out.println(); // prints an empty line

        // printf lets you format values inline using format specifiers
        // %s = String placeholder, %d = integer placeholder, %n = newline
        String productName = "Java Book";
        int quantityInStock = 42;
        double priceInDollars = 29.99;

        System.out.printf("Product : %s%n", productName);
        System.out.printf("In Stock : %d units%n", quantityInStock);

        // %.2f means: print a floating-point number with exactly 2 decimal places
        System.out.printf("Price    : $%.2f%n", priceInDollars);
    }
}
Output
Welcome to TheCodeForge!
First name: Ada Lovelace
Product : Java Book
In Stock : 42 units
Price : $29.99
Pro Tip: Prefer printf for Formatted Data
Any time you're printing a receipt, a table, or a report, reach for printf. It keeps your alignment clean and your code readable. Using string concatenation with + for formatted numbers is fragile and hard to read.
Production Insight
System.out is a PrintStream — it's thread-safe but not meant for high-throughput logging.
In production apps, log files are written via SLF4J/Logback, not System.out.
Rule: use System.out only for CLI tools or debugging; for real services, use a proper logging framework.
Key Takeaway
println adds a newline, print does not.
Use printf for formatting values inline.
System.out.print is not for production logging.

Reading User Input with Scanner — Java's Ears

Printing is only half the story. A program that can't accept input is like a vending machine with no buttons — it just sits there. Java's Scanner class is your go-to tool for reading what a user types into the console.

Scanner lives in the java.util package, so you must import it at the top of your file before you can use it. You create one Scanner object and keep it for the whole program — creating a new Scanner every time you want to read input is wasteful and causes bugs.

Once you have a Scanner, you call different methods depending on what type of data you're expecting. nextLine() reads a whole line of text including spaces. next() reads only one word (stops at a space). nextInt() reads an integer. nextDouble() reads a decimal number. The Scanner pauses the program and waits for the user to type something and press Enter — that pause is called blocking, and it's intentional.

Always close your Scanner when you're done using it. It's connected to a resource (the keyboard input stream), and leaving it open is a memory leak waiting to happen.

UserProfileInput.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.Scanner; // We MUST import Scanner before using it

public class UserProfileInput {
    public static void main(String[] args) {

        // System.in is the keyboard input stream — we wrap it in Scanner to read it easily
        Scanner keyboardInput = new Scanner(System.in);

        // Prompt the user — always print a message BEFORE reading input
        System.out.print("Enter your full name: ");

        // nextLine() reads everything the user types until they press Enter
        String fullName = keyboardInput.nextLine();

        System.out.print("Enter your age: ");

        // nextInt() reads a whole number — it will crash if the user types letters!
        int userAge = keyboardInput.nextInt();

        System.out.print("Enter your account balance: ");

        // nextDouble() reads a decimal number like 1250.75
        double accountBalance = keyboardInput.nextDouble();

        // Print a formatted summary back to the user
        System.out.println("\n--- Profile Summary ---");
        System.out.printf("Name    : %s%n", fullName);
        System.out.printf("Age     : %d years old%n", userAge);
        System.out.printf("Balance : $%.2f%n", accountBalance);

        // Close the Scanner to release the keyboard resource
        keyboardInput.close();
    }
}
Output
Enter your full name: Marie Curie
Enter your age: 35
Enter your account balance: 4820.50
--- Profile Summary ---
Name : Marie Curie
Age : 35 years old
Balance : $4820.50
Watch Out: The nextInt() + nextLine() Trap
If you call nextInt() and then nextLine() immediately after, the nextLine() will return an empty string. Why? nextInt() reads the number but leaves the newline character (Enter key) in the buffer. The nextLine() then instantly consumes that leftover newline. Fix: add an extra keyboardInput.nextLine() after nextInt() to flush the buffer before reading a string.
Production Insight
If you forget to close a Scanner on System.in, it's not a leak — System.in stays open.
But when reading files, an unclosed Scanner leaves the file handle open, eventually exhausting OS limits.
Rule: always close Scanner in a finally block or with try-with-resources.
Key Takeaway
Scanner wraps System.in for easy input reading.
Always close the Scanner when done.
The nextInt/nextLine bug needs explicit buffer flush.

Handling the nextInt/nextLine Bug and Input Validation

This bug trips up almost every beginner, so it deserves its own section. When you mix nextInt() or nextDouble() with nextLine(), the Scanner's internal buffer causes a silent but nasty problem. Let's look at exactly what happens and how to fix it cleanly.

Imagine the user types 25 and presses Enter. What's actually in the buffer is 25 . When you call nextInt(), it reads 25 but leaves the sitting in the buffer. The very next nextLine() sees that and says 'I found a newline — my job is done!' and returns an empty string before the user has a chance to type anything.

The reliable fix is to call keyboardInput.nextLine() immediately after any nextInt() or nextDouble() call — think of it as 'draining the leftover newline from the pipe.' Alternatively, you can read everything as strings using nextLine() and then parse the number yourself with Integer.parseInt() or Double.parseDouble(). The second approach also lets you show a friendly error message when the user types something unexpected instead of crashing.

SafeInputReading.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.Scanner;

public class SafeInputReading {
    public static void main(String[] args) {

        Scanner keyboardInput = new Scanner(System.in);

        // APPROACH 1 — Flush the buffer manually after nextInt()
        System.out.print("Enter your birth year: ");
        int birthYear = keyboardInput.nextInt();

        // This nextLine() drains the leftover '\n' from pressing Enter
        // Without this line, the next nextLine() would return "" (empty string)
        keyboardInput.nextLine(); // <--- the buffer flush

        System.out.print("Enter your home city: ");
        String homeCity = keyboardInput.nextLine(); // now works correctly

        System.out.printf("Born in %d, living in %s.%n", birthYear, homeCity);

        System.out.println();

        // APPROACH 2 — Read everything as String, then parse (safer & more flexible)
        System.out.print("Enter your salary: ");
        String salaryInput = keyboardInput.nextLine(); // read raw text

        double salary;
        try {
            // Parse the string into a number — throws NumberFormatException if invalid
            salary = Double.parseDouble(salaryInput);
            System.out.printf("Annual salary: $%.2f%n", salary);
        } catch (NumberFormatException conversionError) {
            // Friendly message instead of a crash
            System.out.println("That doesn't look like a valid number. Please enter digits only.");
        }

        keyboardInput.close();
    }
}
Output
Enter your birth year: 1990
Enter your home city: London
Born in 1990, living in London.
Enter your salary: 75000.00
Annual salary: $75000.00
Interview Gold: Why Does nextLine() Return Empty After nextInt()?
This exact question comes up in interviews. The answer: nextInt() consumes the numeric token but leaves the newline character in the stream. The immediately following nextLine() reads up to that newline, finds it instantly, and returns an empty string. Calling an extra nextLine() after nextInt() discards that leftover newline.
Production Insight
In a production console app, if you leave the buffer unflushed, user instructions get skipped — the user sees no prompt and data goes missing.
This leads to confusing behaviour that's hard to reproduce.
Rule: after every nextInt/nextDouble, call nextLine() — even if you think you don't need it.
Key Takeaway
nextInt leaves \n in the buffer.
nextLine after nextInt without flush returns empty string.
Fix: read all input as strings and parse manually.

BufferedReader — The Faster, More Powerful Alternative

Scanner is perfect for learning and small programs, but professional Java developers often use BufferedReader for console input instead. The key difference is speed and control — BufferedReader reads large chunks of data at once (buffering them in memory), which is significantly faster when processing big files or high-throughput input.

BufferedReader requires a bit more setup. You wrap System.in in an InputStreamReader (which converts raw bytes to characters) and then wrap that in a BufferedReader (which adds efficient line-by-line reading). It sounds complex, but it's always the same three lines of setup code and you'll memorise them quickly.

The main trade-off: BufferedReader only reads strings — you always get back a String from readLine(), and you have to parse it yourself to get numbers. It also throws a checked IOException which means Java forces you to either handle it with try-catch or declare it with throws IOException. For beginners, Scanner is the right starting point. As you grow into professional Java, reach for BufferedReader.

In the code below, notice how both approaches produce the same result — the choice is about performance and context, not correctness.

BufferedReaderExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.BufferedReader;    // for fast, buffered reading
import java.io.InputStreamReader; // converts raw bytes (System.in) into characters
import java.io.IOException;       // must handle this checked exception

public class BufferedReaderExample {

    // 'throws IOException' tells Java: this method might throw an IO error
    // Java requires us to either handle it or declare it — we're declaring it here
    public static void main(String[] args) throws IOException {

        // Step 1: Wrap System.in in InputStreamReader to handle character encoding
        // Step 2: Wrap that in BufferedReader for efficient line reading
        BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Enter the item name: ");
        String itemName = consoleReader.readLine(); // readLine() always returns a String

        System.out.print("Enter the quantity: ");
        // readLine() gives us "10" as a String — we parse it to int manually
        int quantity = Integer.parseInt(consoleReader.readLine());

        System.out.print("Enter the unit price: ");
        // Similarly, parse the string to a double
        double unitPrice = Double.parseDouble(consoleReader.readLine());

        double totalCost = quantity * unitPrice;

        System.out.println("\n--- Order Receipt ---");
        System.out.printf("Item     : %s%n", itemName);
        System.out.printf("Quantity : %d%n", quantity);
        System.out.printf("Unit Price: $%.2f%n", unitPrice);
        System.out.printf("Total    : $%.2f%n", totalCost);

        consoleReader.close(); // always close your reader
    }
}
Output
Enter the item name: Mechanical Keyboard
Enter the quantity: 3
Enter the unit price: 89.99
--- Order Receipt ---
Item : Mechanical Keyboard
Quantity : 3
Unit Price: $89.99
Total : $269.97
Pro Tip: Use try-with-resources to Auto-Close Readers
Instead of calling close() manually (and risking forgetting it), wrap your BufferedReader in a try-with-resources block: try (BufferedReader reader = new BufferedReader(...)) { ... }. Java will automatically close it when the block ends, even if an exception is thrown. This is the professional pattern.
Production Insight
BufferedReader is the standard for reading large files in production — its default buffer size is 8KB.
Scanner tokenises every read, adding ~0.5ms per nextXxx call, which adds up quickly in batch jobs.
Rule: use BufferedReader for any I/O that processes more than a few hundred lines.
Key Takeaway
BufferedReader wraps System.in with InputStreamReader for efficient line reading.
It only reads strings — you parse numbers manually.
Use try-with-resources to auto-close.

Reading from Files with Scanner and Writing with PrintWriter

Console input is just the start. In real applications, input often comes from files — configuration files, data logs, CSV exports. Java's Scanner can read from files just as easily as from the keyboard. You just pass a File object instead of System.in. For writing output to files, PrintWriter is the equivalent of System.out.

Scanner automatically handles different data types when reading from files. hasNextLine() is your friend here — it returns true if there's another line in the file, letting you loop safely without hitting NoSuchElementException. For writing, PrintWriter provides println, print, and printf just like System.out. But you must flush or close it to ensure data actually hits the disk.

The common mistake is assuming Scanner will skip empty lines or that PrintWriter automatically flushes. PrintWriter's autoFlush is false by default — if you forget to close, you lose output.

Let's see a complete example: reading customer data from a CSV file and writing a formatted report to another file.

FileIOExample.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;

public class FileIOExample {
    public static void main(String[] args) {
        // Input file: customers.csv
        // Each line: id,name,balance
        File inputFile = new File("customers.csv");
        File outputFile = new File("report.txt");

        // Use try-with-resources to auto-close both Scanner and PrintWriter
        try (Scanner fileScanner = new Scanner(inputFile);
             PrintWriter writer = new PrintWriter(outputFile)) {

            // Skip header line
            if (fileScanner.hasNextLine()) {
                fileScanner.nextLine();
            }

            writer.println("Customer Report");
            writer.println("===============");

            while (fileScanner.hasNextLine()) {
                String line = fileScanner.nextLine();
                String[] parts = line.split(",");
                if (parts.length == 3) {
                    int id = Integer.parseInt(parts[0].trim());
                    String name = parts[1].trim();
                    double balance = Double.parseDouble(parts[2].trim());
                    writer.printf("ID: %d | Name: %s | Balance: $%.2f%n", id, name, balance);
                } else {
                    System.err.println("Skipping malformed line: " + line);
                }
            }

            System.out.println("Report generated: " + outputFile.getAbsolutePath());

        } catch (FileNotFoundException e) {
            System.err.println("File not found: " + e.getMessage());
        } catch (NumberFormatException e) {
            System.err.println("Number format error in file: " + e.getMessage());
        }
    }
}
Output
(no console output except confirmation message; report.txt written to disk)
Watch Out: FileNotFoundException Is Checked
Both Scanner(File) and PrintWriter(File) throw FileNotFoundException, a checked exception. You must either catch it or declare it in the method signature. Using try-with-resources handles the close but you still need to handle the exception.
Production Insight
In a production batch job, forgetting to close a PrintWriter can lose the last few lines of output — PrintWriter buffers internally.
A power loss or JVM crash before flush() means data loss.
Rule: always flush or close in a finally block, or better, use try-with-resources.
Key Takeaway
Scanner can read files by passing a File object.
PrintWriter writes formatted output to files.
Always close or use try-with-resources to avoid data loss.
● Production incidentPOST-MORTEMseverity: high

Unclosed Scanner in Batch Job Exhausts File Handles

Symptom
After processing ~1020 files, the batch job throws java.io.FileNotFoundException: (Too many open files) even though the files exist.
Assumption
The team assumed that because each file is small, creating a new Scanner per file and letting it go out of scope would automatically release resources.
Root cause
Scanner wraps a FileInputStream that must be explicitly closed. Java garbage collection does not close native resources promptly. The OS file descriptor limit (default 1024 on Linux) was exhausted.
Fix
Wrapped every Scanner instantiation in a try-with-resources block (try (Scanner sc = new Scanner(file)) { ... }) to ensure automatic closure. Added a monitoring alert for file descriptor usage.
Key lesson
  • Always close I/O resources — never rely on garbage collection.
  • Use try-with-resources for any resource that implements AutoCloseable.
  • Monitor file descriptor count on production servers.
Production debug guideSymptom → Action guide for common Scanner/BufferedReader failures4 entries
Symptom · 01
NoSuchElementException or InputMismatchException when reading from System.in
Fix
Check that System.in hasn't been closed prematurely. Don't call System.in.close() unless you intend to. Use hasNextLine/hasNextInt before reading.
Symptom · 02
FileNotFoundException: Too many open files
Fix
Run lsof -p <pid> | wc -l to check open file handles. Find unclosed Scanner/BufferedReader instances and wrap them in try-with-resources.
Symptom · 03
Scanner reads empty strings after nextInt
Fix
Add scanner.nextLine() after nextInt to flush the newline buffer. Alternatively, switch to reading all input as strings.
Symptom · 04
BufferedReader.readLine() returns null unexpectedly
Fix
Check if the end of stream was reached. Loop while (line = reader.readLine()) != null. Also verify that the InputStream hasn't been closed externally.
★ Quick Debug Cheat Sheet — Java I/OFast diagnostics for the most common input/output problems in Java console and file applications.
Next-line read returns empty string after a numeric input
Immediate action
Add a throwaway nextLine() after the numeric read.
Commands
scanner.nextLine(); // drain newline
String text = scanner.nextLine(); // now reads correctly
Fix now
Insert scanner.nextLine(); immediately after every nextInt/nextDouble/nextFloat call before reading a line.
Too many open files error+
Immediate action
Check open file handles with `lsof -p <pid>` on Linux.
Commands
lsof -p $(pgrep -f YourMainClass) | wc -l
grep -r "new Scanner" src/ --include="*.java" | wc -l
Fix now
Wrap each Scanner in try-with-resources: try (Scanner sc = new Scanner(file)) { ... }
InputMismatchException when expecting a number+
Immediate action
Use hasNextInt/hasNextDouble to check before reading.
Commands
if (scanner.hasNextInt()) { int val = scanner.nextInt(); }
String raw = scanner.nextLine(); try { int val = Integer.parseInt(raw.trim()); } catch (NumberFormatException e) { ... }
Fix now
Read raw string and parse with exception handling instead of using nextInt directly.
FeatureScannerBufferedReader
Import neededjava.util.Scannerjava.io.BufferedReader + InputStreamReader
Reads numbers directly?Yes — nextInt(), nextDouble()No — must parse strings manually
Handles newline after nextInt?No — requires manual buffer flushNot an issue — always reads whole lines
PerformanceSlower (tokenises input)Faster (buffers large chunks)
Exception handling required?No checked exceptionsYes — must handle IOException
Best forBeginner projects, simple console appsProfessional apps, file reading, performance-critical code
Setup complexitySimple — one lineModerate — three wrapped classes

Key takeaways

1
System.out.println() adds a newline after printing; System.out.print() doesn't
mix them intentionally to control exactly where your cursor lands.
2
Scanner requires import java.util.Scanner and must be wrapped around System.in
create one instance and reuse it, never create a new Scanner per read operation.
3
The nextInt() + nextLine() buffer bug is one of the most common beginner traps in Java
always flush the buffer with an extra nextLine() after reading a number if you plan to read a string next.
4
BufferedReader is faster and more professional than Scanner but requires more setup and manual number parsing
start with Scanner, graduate to BufferedReader as your programs grow.
5
When reading files, always close resources
the best way is try-with-resources, which auto-closes even on exceptions.

Common mistakes to avoid

4 patterns
×

Calling nextLine() immediately after nextInt() without buffer flush

Symptom
nextLine() returns an empty string silently, causing downstream logic to fail with blank data or wrong output.
Fix
Add a throwaway keyboardInput.nextLine() call right after nextInt() or nextDouble() to consume the leftover newline character before reading your actual string.
×

Forgetting to import Scanner

Symptom
Compiler throws 'cannot find symbol: class Scanner' even though the code looks correct.
Fix
Add import java.util.Scanner; as the very first line after your package declaration. This import is mandatory; Scanner is not automatically available like System is.
×

Using nextLine() to read a number and skipping parseInt/parseDouble conversion

Symptom
Program compiles and runs but stores '42' as a String, causing 'incompatible types' error when you try arithmetic.
Fix
Always convert with Integer.parseInt(stringValue) or Double.parseDouble(stringValue) and wrap in a try-catch to handle invalid input gracefully.
×

Not closing Scanner when reading a file

Symptom
File handle remains open, eventually hitting OS limit (too many open files).
Fix
Use try-with-resources: try (Scanner sc = new Scanner(new File("data.txt"))) { ... } — Java closes it automatically.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between System.out.print(), System.out.println(),...
Q02SENIOR
Why does calling nextLine() immediately after nextInt() on the same Scan...
Q03SENIOR
What are the advantages of using BufferedReader over Scanner for reading...
Q01 of 03JUNIOR

What is the difference between System.out.print(), System.out.println(), and System.out.printf() in Java? When would you choose each one?

ANSWER
print outputs text without a newline. println appends a newline after output. printf uses format specifiers for structured formatting. Use printf for reports or tables where alignment matters. Use print for prompts. Use println for general output.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
How do I read user input in Java?
02
What is the difference between print and println in Java?
03
Do I always need to import Scanner in Java?
04
When should I use BufferedReader instead of Scanner?
🔥

That's Java Basics. Mark it forged?

4 min read · try the examples if you haven't

Previous
Type Casting in Java
8 / 13 · Java Basics
Next
Comments in Java