{"id":"reading-files-name-from-user","slug":"a-file-chosen-by-the-user","title":"A file chosen by the user","text":"A program is more useful when the user can pick the file. It then needs two Scanners: one for the keyboard and one for the file, each with a name of its own:\n\n```file shopping.txt\napples\nbread\ncoffee\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        Scanner scanner = new Scanner(System.in);\n        System.out.println(\"Which file?\");\n        String fileName = scanner.nextLine();\n\n        try (Scanner fileScanner = new Scanner(Paths.get(fileName))) {\n            while (fileScanner.hasNextLine()) {\n                System.out.println(fileScanner.nextLine());\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n    }\n}\n```\n\n```input\nshopping.txt\n```\n\n```output\nWhich file?\napples\nbread\ncoffee\n```\n\n- `scanner` reads the keyboard, and `fileScanner` reads the file. Mixing them up is an easy slip: `scanner.nextLine()` inside the loop would read the keyboard, not the file.\n- `Paths.get(fileName)` takes any String, here the name the user typed.\n- A name that doesn't exist, such as `shoping.txt`, ends up in the `catch` block, and the program prints `Error: shoping.txt`.\n- The keyboard Scanner isn't put in a `try (...)`. Closing it would close the keyboard input as well, and nothing more could be read from it.\n","task":"The program reads a file name and prints how many lines that file has. Fill in the blanks. For the input `monday.txt` and the files shown below, it prints:\n\n```\nWhich file?\nmonday.txt: 3 lines\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        Scanner scanner = new Scanner(System.in);\n        System.out.println(\"Which file?\");\n        String fileName = scanner.nextLine();\n        int lines = 0;\n        try (Scanner fileScanner = new Scanner(Paths.get([[fileName]]))) {\n            while ([[fileScanner]].hasNextLine()) {\n                fileScanner.nextLine();\n                lines++;\n            }\n            System.out.println(fileName + \": \" + lines + \" lines\");\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        Scanner scanner = new Scanner(System.in);\n        System.out.println(\"Which file?\");\n        String fileName = scanner.nextLine();\n        int lines = 0;\n        try (Scanner fileScanner = new Scanner(Paths.get(fileName))) {\n            while (fileScanner.hasNextLine()) {\n                fileScanner.nextLine();\n                lines++;\n            }\n            System.out.println(fileName + \": \" + lines + \" lines\");\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n    }\n}\n","hints":["The file to open is the one the user named: the variable `fileName`, without quotes.","The loop asks the file's Scanner, `fileScanner`, whether it has lines left."],"tests":[{"name":"Test 1","stdin":"monday.txt\n","files":{"monday.txt":"gym\ngroceries\ncall Sam\n","tuesday.txt":"dentist\nlaundry\npay the bills\nread\npizza night\n"},"expect":"Which file?\nmonday.txt: 3 lines","hidden":false},{"name":"Test 2","stdin":"tuesday.txt\n","files":{"monday.txt":"gym\ngroceries\ncall Sam\n","tuesday.txt":"dentist\nlaundry\npay the bills\nread\npizza night\n"},"expect":"Which file?\ntuesday.txt: 5 lines","hidden":true},{"name":"Test 3","stdin":"friday.txt\n","files":{"monday.txt":"gym\n"},"expect":"Which file?\nError: friday.txt","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Read a file name and then a line number. Print that line of the file: line 1 is the first one. If the file has fewer lines than that, print `The file has only ` and its number of lines, followed by ` lines`. The program prints no questions. For the input `poem.txt` and `2` and the files shown below, it prints:\n\n```\nthe cat pretends to sleep\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        Scanner scanner = new Scanner(System.in);\n        String fileName = scanner.nextLine();\n        int number = Integer.valueOf(scanner.nextLine());\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        Scanner scanner = new Scanner(System.in);\n        String fileName = scanner.nextLine();\n        int number = Integer.valueOf(scanner.nextLine());\n\n        ArrayList<String> lines = new ArrayList<>();\n        try (Scanner fileScanner = new Scanner(Paths.get(fileName))) {\n            while (fileScanner.hasNextLine()) {\n                lines.add(fileScanner.nextLine());\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n\n        if (number <= lines.size()) {\n            System.out.println(lines.get(number - 1));\n        } else {\n            System.out.println(\"The file has only \" + lines.size() + \" lines\");\n        }\n    }\n}\n","hints":["Read the file's lines into a list, with a Scanner of its own: `new Scanner(Paths.get(fileName))`.","Line 1 is at index 0, so line `number` is `lines.get(number - 1)`. Check `number <= lines.size()` first."],"tests":[{"name":"Test 1","stdin":"poem.txt\n2\n","files":{"poem.txt":"the kettle hums at seven\nthe cat pretends to sleep\nrain taps on the window\nand Monday starts again\n","rules.txt":"No running\nNo shouting\nHave fun\n"},"expect":"the cat pretends to sleep","hidden":false},{"name":"Test 2","stdin":"rules.txt\n3\n","files":{"poem.txt":"the kettle hums at seven\nthe cat pretends to sleep\nrain taps on the window\nand Monday starts again\n","rules.txt":"No running\nNo shouting\nHave fun\n"},"expect":"Have fun","hidden":true},{"name":"Test 3","stdin":"poem.txt\n9\n","files":{"poem.txt":"the kettle hums at seven\nthe cat pretends to sleep\nrain taps on the window\nand Monday starts again\n"},"expect":"The file has only 4 lines","hidden":true},{"name":"Test 4","stdin":"rules.txt\n1\n","files":{"rules.txt":"No running\nNo shouting\nHave fun\n"},"expect":"No running","hidden":true}],"require":[],"forbid":[]},{"task":"Write a method `countLines(String fileName)` that returns how many lines the file has, or `-1` if the file can't be read. The check runs `System.out.println(countLines(\"draft.txt\"));` with the file shown below, and expects:\n\n```\n4\n```\n","kind":"code","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(countLines(\"draft.txt\"));\n    }\n\n    // Write the countLines method here.\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(countLines(\"draft.txt\"));\n    }\n\n    public static int countLines(String fileName) {\n        int count = 0;\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                scanner.nextLine();\n                count++;\n            }\n        } catch (Exception e) {\n            return -1;\n        }\n        return count;\n    }\n}\n","hints":["The method opens `Paths.get(fileName)`, the name it was given, and counts in a `hasNextLine()` loop. Call `scanner.nextLine();` in every round to move on to the next line.","`return -1;` in the `catch` block, and `return count;` after the whole `try`/`catch`."],"tests":[{"name":"System.out.println(countLines(\"draft.txt\"));","stdin":"","call":"System.out.println(countLines(\"draft.txt\"));\n","files":{"draft.txt":"Dear Mia,\nthanks for the letter.\nSee you soon,\nLeo\n"},"expect":"4","hidden":false},{"name":"System.out.println(countLines(\"final.txt\"));","stdin":"","call":"System.out.println(countLines(\"final.txt\"));\n","files":{"draft.txt":"Dear Mia,\nthanks for the letter.\nSee you soon,\nLeo\n","final.txt":"Hi Mia, see you on Friday!\nLeo\n"},"expect":"2","hidden":true},{"name":"System.out.println(countLines(\"missing.txt\"));","stdin":"","call":"System.out.println(countLines(\"missing.txt\"));\n","files":{"draft.txt":"Dear Mia,\n"},"expect":"-1","hidden":true},{"name":"System.out.println(countLines(\"a.txt\") + countLines(\"b.txt\"));","stdin":"","call":"System.out.println(countLines(\"a.txt\") + countLines(\"b.txt\"));\n","files":{"a.txt":"1\n2\n3\n","b.txt":"4\n5\n6\n7\n8\n"},"expect":"8","hidden":true}],"require":[],"forbid":[]}]}