{"id":"reading-files-reading","slug":"reading-a-file","title":"Reading a file line by line","text":"Here's the program from the previous step again, this time printing each line as it is:\n\n```file plants.txt\nbasil\nmint\nrosemary\n```\n\n```java\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        try (Scanner scanner = new Scanner(Paths.get(\"plants.txt\"))) {\n            while (scanner.hasNextLine()) {\n                String line = scanner.nextLine();\n                System.out.println(line);\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n    }\n}\n```\n\n```output\nbasil\nmint\nrosemary\n```\n\nIts parts:\n\n- `Paths.get(\"plants.txt\")` turns the file's name into a **path**, Java's way of pointing to a file. `Paths` needs its own import at the top: `import java.nio.file.Paths;`.\n- `new Scanner(...)` with a path makes a Scanner that reads the file instead of the keyboard (`System.in`). Its `nextLine()` works like the keyboard's: each call gives the next line, without the line break at its end.\n- `scanner.hasNextLine()` works as it did on the keyboard in the first step: it's `true` until every line has been read, so the loop runs once for each line of the file and then stops.\n- `try (...)` opens the file for the block after it and **closes** it when the block ends. A program should close a file when it's done with it, and this form of `try`, called **try-with-resources**, does that for you. The Scanner exists only inside the block's braces.\n- `catch (Exception e) { ... }` is what happens when the reading fails, for example because there's no such file. The next step is about it.\n\nEvery round of the loop must call `nextLine()`. `hasNextLine()` only looks: if nothing reads the line, the same line stays waiting, `hasNextLine()` stays `true`, and the loop never ends.\n\n### Keeping the lines in a list\n\nThe loop sees each line once. When the program needs the lines afterwards, for example to know how many there are or to use them in another order, it adds them to a list:\n\n```file plants.txt\nbasil\nmint\nrosemary\n```\n\n```java\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> plants = new ArrayList<>();\n        try (Scanner scanner = new Scanner(Paths.get(\"plants.txt\"))) {\n            while (scanner.hasNextLine()) {\n                plants.add(scanner.nextLine());\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Plants: \" + plants.size());\n        System.out.println(\"The last one: \" + plants.get(plants.size() - 1));\n    }\n}\n```\n\n```output\nPlants: 3\nThe last one: rosemary\n```\n\nThe list is made before the `try`, so it still exists after the block. A variable made inside the braces would be gone by then.\n\n### A Scanner can read a String too\n\n`new Scanner(...)` also takes a String, and then reads it as if it were a file. Inside quotes, `\\n` stands for a line break, so the String below holds two lines. A String can't go missing, so no `try` is needed. It's a quick way to try out a loop, and some of the practice questions use it:\n\n```java\nScanner scanner = new Scanner(\"first line\\nsecond line\");\nwhile (scanner.hasNextLine()) {\n    System.out.println(\"> \" + scanner.nextLine());\n}\n```\n\n```output\n> first line\n> second line\n```\n","task":"Fill in the blanks, so the program prints every line of `todo.txt` with its number in front. For the file shown below, it prints:\n\n```\n1. buy stamps\n2. call the dentist\n3. water the plants\n```\n","kind":"fill","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        int number = 0;\n        try (Scanner scanner = new Scanner(Paths.get(\"todo.txt\"))) {\n            while (scanner.[[hasNextLine]]()) {\n                String task = scanner.[[nextLine]]();\n                number++;\n                System.out.println(number + \". \" + task);\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        int number = 0;\n        try (Scanner scanner = new Scanner(Paths.get(\"todo.txt\"))) {\n            while (scanner.hasNextLine()) {\n                String task = scanner.nextLine();\n                number++;\n                System.out.println(number + \". \" + task);\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n    }\n}\n","hints":["The loop's condition asks whether there's a line left: `hasNextLine`.","Inside the loop, `nextLine` reads the line."],"tests":[{"name":"Test 1","stdin":"","files":{"todo.txt":"buy stamps\ncall the dentist\nwater the plants\n"},"expect":"1. buy stamps\n2. call the dentist\n3. water the plants","hidden":false},{"name":"Test 2","stdin":"","files":{"todo.txt":"fix the bike\nreturn the library books\nbake bread\nwrite to grandma\nclean the windows\n"},"expect":"1. fix the bike\n2. return the library books\n3. bake bread\n4. write to grandma\n5. clean the windows","hidden":true}],"require":[],"forbid":[],"more":[{"task":"The file `queue.txt` lists the people in a queue, one name per line, from the front of the queue to the back. Print how many people are in the queue, who is first and who is last. The file has at least one name. For the file shown below, the program prints:\n\n```\nIn the queue: 4\nFirst: Oona\nLast: Tariq\n```\n","kind":"code","seed":"import java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> names = new ArrayList<>();\n        try (Scanner scanner = new Scanner(Paths.get(\"queue.txt\"))) {\n            while (scanner.hasNextLine()) {\n                names.add(scanner.nextLine());\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"In the queue: \" + names.size());\n        System.out.println(\"First: \" + names.get(0));\n        System.out.println(\"Last: \" + names.get(names.size() - 1));\n    }\n}\n","hints":["Read every line into an `ArrayList<String>` made before the `try`, as in the example above.","After the `try`, the first name is `names.get(0)` and the last one `names.get(names.size() - 1)`."],"tests":[{"name":"Test 1","stdin":"","files":{"queue.txt":"Oona\nWilma\nKasper\nTariq\n"},"expect":"In the queue: 4\nFirst: Oona\nLast: Tariq","hidden":false},{"name":"Test 2","stdin":"","files":{"queue.txt":"Mei\n"},"expect":"In the queue: 1\nFirst: Mei\nLast: Mei","hidden":true},{"name":"Test 3","stdin":"","files":{"queue.txt":"Arvo\nBea\nChidi\nDora\nEmil\nFatima\n"},"expect":"In the queue: 6\nFirst: Arvo\nLast: Fatima","hidden":true}],"require":[{"pattern":"\\.hasNextLine\\s*\\(","message":"Read the file with a `hasNextLine()` loop."}],"forbid":[]},{"task":"This program reads a String with a Scanner. What does it print? Look closely at the String: `\\n` is a line break.\n","kind":"predict","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(\"ant\\nbee\\n\\ncat\");\n        int lines = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            lines++;\n            System.out.println(lines + \": \" + line.length());\n        }\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(\"ant\\nbee\\n\\ncat\");\n        int lines = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            lines++;\n            System.out.println(lines + \": \" + line.length());\n        }\n    }\n}\n","hints":["Two line breaks in a row, `\\n\\n`, leave an empty line between them.","An empty line is a line too: it's read and counted, and its length is 0."],"tests":[{"name":"Output","stdin":"","expect":"1: 3\n2: 3\n3: 0\n4: 3","hidden":false}],"require":[],"forbid":[],"lines":["1: 3","2: 3","3: 0","4: 3"]}]}