{"id":"writing-files-printwriter","slug":"printwriter","title":"Writing a file with PrintWriter","text":"Module 20 read files that were already there. This module writes them. Everything a program keeps in its variables is gone when it ends, so a program that should remember something until the next time it runs, such as a shopping list, a high-score table or a to-do list, saves it in a file and reads it back when it starts again.\n\n### PrintWriter\n\nThe class `PrintWriter`, in the package `java.io`, writes text into a file. Its methods are named like those of `System.out`, so you know them already:\n\n```java\nimport java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        PrintWriter writer = new PrintWriter(\"shopping.txt\");\n        writer.println(\"oat milk\");\n        writer.println(\"rye bread\");\n        writer.print(\"apples\");\n        writer.println(\", 6\");\n        writer.close();\n        System.out.println(\"List saved\");\n    }\n}\n```\n\n```output\nList saved\n```\n\nOnly `List saved` appears in the output: it's the only text printed with `System.out`. The rest went into a file. After the run, the program's working folder has a file called `shopping.txt`, and it holds:\n\n```text\noat milk\nrye bread\napples, 6\n```\n\n- `new PrintWriter(\"shopping.txt\")` opens the file `shopping.txt` for writing. A name alone means a file in the working folder, as in module 20. When there's no file by that name, it's created. When there is one, it's emptied first, so what the program writes replaces what the file held. (The next step shows how to add to a file instead.)\n- `writer.println(...)` writes the text and a line break into the file, as `System.out.println` does on the screen. `writer.print(...)` writes the text without a line break, so whatever comes next goes on the same line: `apples` and `, 6` make one line.\n- `writer.close()` closes the file once the program is done with it. Don't leave it out: the next section shows why.\n- `throws Exception` in `main`'s header is there because creating a PrintWriter may throw an exception. The last section of this step is about it.\n\nOn Java Arena, **Run with my input** shows the files your program created or changed below its output, each under its name. The checks of this module look at those files too. Each test runs your program in a folder of its own, which holds only the files the task gives, and then compares the files your program should have written with the ones the model solution wrote, the same way it compares the output: line endings, spaces at the ends of lines and blank lines at the end don't matter; everything else does.\n\n### Close the file\n\nA PrintWriter doesn't send each `println` to the file right away. It gathers the text in memory and writes it to the file in larger pieces, which is much faster than writing every line on its own. `close()` writes whatever is still waiting, and then gives the file back to the operating system: an open file is a resource, as module 42 said. When the program ends, the operating system takes the file back, as it does with everything a program has open, but nothing calls the PrintWriter's `close()`, so the text still waiting in memory never reaches the file. A program that never calls `close()` can leave the file empty.\n\nThis program forgets to close its writer, and then reads the file back with a Scanner, as module 20 did:\n\n```java\nimport java.io.PrintWriter;\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        PrintWriter writer = new PrintWriter(\"reminders.txt\");\n        writer.println(\"Call the dentist\");\n        writer.println(\"Buy stamps\");\n\n        int lines = 0;\n        try (Scanner reader = new Scanner(Paths.get(\"reminders.txt\"))) {\n            while (reader.hasNextLine()) {\n                System.out.println(\"Read: \" + reader.nextLine());\n                lines++;\n            }\n        }\n        System.out.println(\"Lines read: \" + lines);\n    }\n}\n```\n\n```output\nLines read: 0\n```\n\nCreating the PrintWriter created the file, but the two lines were still waiting in memory, so the file was empty when the Scanner read it. With `writer.close();` right after the second `println`, the same program prints `Read: Call the dentist`, `Read: Buy stamps` and `Lines read: 2`.\n\n(The try-with-resources that reads the file has no `catch` block: `main` passes exceptions on with `throws Exception`, which module 42 said is enough.)\n\n### The exception\n\nOpening a file for writing can fail. The name might belong to a folder, the folder the file should go in might not exist, or the program might not be allowed to write there. PrintWriter's constructor then throws a `FileNotFoundException`. That's a kind of IOException, and so a checked exception (module 42): the program must catch it or declare it. With neither, javac refuses the program:\n\n```java\nimport java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) {\n        PrintWriter writer = new PrintWriter(\"shopping.txt\");\n        writer.println(\"oat milk\");\n        writer.close();\n    }\n}\n```\n\n```javac\nMain.java:5: error: unreported exception FileNotFoundException; must be caught or declared to be thrown\n        PrintWriter writer = new PrintWriter(\"shopping.txt\");\n                             ^\n1 error\n```\n\nYou have module 42's two choices.\n\n**Declare it.** `throws Exception` in `main`'s header passes the exception on to Java, which stops the program with a report when it happens. That's what the examples above do, and the MOOC's examples do the same. Here the file should go into a folder called `backup`, which doesn't exist:\n\n```java\nimport java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        PrintWriter writer = new PrintWriter(\"backup/shopping.txt\");\n        writer.println(\"oat milk\");\n        writer.close();\n    }\n}\n```\n\n```crash\nException in thread \"main\" java.io.FileNotFoundException: backup/shopping.txt (No such file or directory)\n\tat Main.main(Main.java:5)\n```\n\nA PrintWriter creates the file, but not the folders on the way to it. A method of your own that writes a file can declare the exception in the same way, such as `public static void saveList(String fileName) throws Exception`, and then the code that calls it has the same two choices.\n\n**Catch it.** A `try` around the writing lets the program go on, and tell the user what went wrong:\n\n```java\nimport java.io.FileNotFoundException;\nimport java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) {\n        String[] names = {\"shopping.txt\", \"backup/shopping.txt\"};\n        for (String name : names) {\n            try {\n                PrintWriter writer = new PrintWriter(name);\n                writer.println(\"oat milk\");\n                writer.close();\n                System.out.println(\"Saved \" + name);\n            } catch (FileNotFoundException e) {\n                System.out.println(\"Could not save \" + name);\n            }\n        }\n    }\n}\n```\n\n```output\nSaved shopping.txt\nCould not save backup/shopping.txt\n```\n","task":"A time capsule program reads lines until the input ends, writes each of them into the file `capsule.txt`, and at the end prints how many lines it sealed in. Fill in the blanks. For the input shown below, it prints:\n\n```\nSealed 3 lines\n```\n\nand `capsule.txt` then holds the same three lines as the input.\n","kind":"fill","seed":"import java.io.PrintWriter;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        Scanner scanner = new Scanner(System.in);\n        PrintWriter writer = new [[PrintWriter]](\"capsule.txt\");\n        int count = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            writer.[[println]](line);\n            count++;\n        }\n        writer.[[close]]();\n        System.out.println(\"Sealed \" + count + \" lines\");\n    }\n}\n","solution":"import java.io.PrintWriter;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        Scanner scanner = new Scanner(System.in);\n        PrintWriter writer = new PrintWriter(\"capsule.txt\");\n        int count = 0;\n        while (scanner.hasNextLine()) {\n            String line = scanner.nextLine();\n            writer.println(line);\n            count++;\n        }\n        writer.close();\n        System.out.println(\"Sealed \" + count + \" lines\");\n    }\n}\n","hints":["The first blank is the class that writes a file. The second writes a line and its line break into the file, as `System.out`'s method of the same name does on the screen.","The last blank closes the file, so that the lines really reach it: `writer.close()`."],"tests":[{"name":"Test 1","stdin":"Dear me in ten years,\ndid the lemon tree survive?\nLove, me\n","writes":{"capsule.txt":"Dear me in ten years,\ndid the lemon tree survive?\nLove, me"},"expect":"Sealed 3 lines","hidden":false},{"name":"Test 2","stdin":"Hello from the past\nSee you in 2036\n","writes":{"capsule.txt":"Hello from the past\nSee you in 2036"},"expect":"Sealed 2 lines","hidden":true},{"name":"Test 3","stdin":"Top song: Blue Rain\nBest friend: Noor\nHeight: 142 cm\nBike: red\nDream: to see a whale\n","writes":{"capsule.txt":"Top song: Blue Rain\nBest friend: Noor\nHeight: 142 cm\nBike: red\nDream: to see a whale"},"expect":"Sealed 5 lines","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A shop writes the sign for its door with `print` and `println`, and then reads the file back, printing each line between brackets after its number. What does the program print?\n","kind":"predict","seed":"import java.io.PrintWriter;\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        PrintWriter writer = new PrintWriter(\"sign.txt\");\n        writer.print(\"Open\");\n        writer.println(\" daily\");\n        writer.println();\n        writer.print(\"Closed\");\n        writer.print(\" on May 1\");\n        writer.close();\n\n        try (Scanner reader = new Scanner(Paths.get(\"sign.txt\"))) {\n            int number = 1;\n            while (reader.hasNextLine()) {\n                System.out.println(number + \" [\" + reader.nextLine() + \"]\");\n                number++;\n            }\n        }\n    }\n}\n","solution":"import java.io.PrintWriter;\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        PrintWriter writer = new PrintWriter(\"sign.txt\");\n        writer.print(\"Open\");\n        writer.println(\" daily\");\n        writer.println();\n        writer.print(\"Closed\");\n        writer.print(\" on May 1\");\n        writer.close();\n\n        try (Scanner reader = new Scanner(Paths.get(\"sign.txt\"))) {\n            int number = 1;\n            while (reader.hasNextLine()) {\n                System.out.println(number + \" [\" + reader.nextLine() + \"]\");\n                number++;\n            }\n        }\n    }\n}\n","hints":["`print` doesn't end the line, so `Open` and ` daily` end up on one line. `println()` with nothing in the parentheses writes only a line break, which makes an empty line.","The last two `print`s aren't followed by a line break, but their text is still a line of the file: the last one."],"tests":[{"name":"Output","stdin":"","expect":"1 [Open daily]\n2 []\n3 [Closed on May 1]","hidden":false}],"require":[],"forbid":[],"lines":["1 [Open daily]","2 []","3 [Closed on May 1]"]},{"task":"A teacher wants practice sheets for the multiplication table. Write the method `writeGrid(String fileName, int size)`, which writes a grid of products into the file: `size` lines, where line number `row` (counting from 1) holds `row * 1`, `row * 2` and so on up to `row * size`, with a space between the numbers. The method prints nothing. Creating a PrintWriter may throw, so the method's header needs `throws Exception`.\n\nThe check runs `writeGrid(\"grid.txt\", 4);`, and after it `grid.txt` should hold:\n\n```text\n1 2 3 4\n2 4 6 8\n3 6 9 12\n4 8 12 16\n```\n","kind":"code","seed":"import java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        writeGrid(\"grid.txt\", 4);\n    }\n\n    public static void writeGrid(String fileName, int size) {\n        // Write the grid into the file here.\n    }\n}\n","solution":"import java.io.PrintWriter;\n\npublic class Main {\n    public static void main(String[] args) throws Exception {\n        writeGrid(\"grid.txt\", 4);\n    }\n\n    public static void writeGrid(String fileName, int size) throws Exception {\n        PrintWriter writer = new PrintWriter(fileName);\n        for (int row = 1; row <= size; row++) {\n            for (int column = 1; column <= size; column++) {\n                writer.print(row * column);\n                if (column < size) {\n                    writer.print(\" \");\n                }\n            }\n            writer.println();\n        }\n        writer.close();\n    }\n}\n","hints":["Two loops, one inside the other: the outer one goes through the rows and the inner one through the columns. `writer.print(row * column + \" \")` writes a number and a space without ending the line. A space at the end of a line doesn't matter to the check.","After the inner loop, `writer.println()` ends the row. After both loops, `writer.close()`. And add `throws Exception` after the method's parentheses."],"tests":[{"name":"writeGrid(\"grid.txt\", 4);","stdin":"","call":"writeGrid(\"grid.txt\", 4);\n","writes":{"grid.txt":"1 2 3 4\n2 4 6 8\n3 6 9 12\n4 8 12 16"},"expect":"","hidden":false},{"name":"writeGrid(\"one.txt\", 1);","stdin":"","call":"writeGrid(\"one.txt\", 1);\n","writes":{"one.txt":"1"},"expect":"","hidden":true},{"name":"writeGrid(\"sheet.txt\", 7);","stdin":"","call":"writeGrid(\"sheet.txt\", 7);\n","writes":{"sheet.txt":"1 2 3 4 5 6 7\n2 4 6 8 10 12 14\n3 6 9 12 15 18 21\n4 8 12 16 20 24 28\n5 10 15 20 25 30 35\n6 12 18 24 30 36 42\n7 14 21 28 35 42 49"},"expect":"","hidden":true},{"name":"Test 4","stdin":"","call":"writeGrid(\"grid.txt\", 5);\nwriteGrid(\"grid.txt\", 2);\n","writes":{"grid.txt":"1 2\n2 4"},"expect":"","hidden":true}],"require":[],"forbid":[]}]}