{"id":"writing-files-rewrite","slug":"clear-and-delete","title":"Clearing, rewriting and deleting files","text":"### Clearing a file\n\nOpening a file with `\"w\"` empties it. So to clear a file, open it with `\"w\"` and write nothing. But a `with` block can't be empty: Python requires at least one statement in every indented block. For a block that should do nothing, Python has the statement **`pass`**, which does exactly nothing:\n\n```file log.txt\nold line 1\nold line 2\n```\n\n```python\nwith open(\"log.txt\", \"w\") as file:\n    pass\n\nwith open(\"log.txt\") as file:\n    contents = file.read()\nprint(len(contents))\n```\n\n```output\n0\n```\n\nYou have seen `pass` before: the starter code of a function task has `pass` as the function's body, so that the program runs before the real body is written.\n\n### Changing lines in the middle\n\n`\"a\"` can only add to the end, and `\"w\"` starts from an empty file. To change or remove something in the middle of a file, a program reads the whole file into a list, changes the list, and writes the whole list back with `\"w\"`:\n\n```file tasks.txt\nwash the car\nbuy stamps\ncall the bank\n```\n\n```python\ntasks = []\nwith open(\"tasks.txt\") as file:\n    for line in file:\n        tasks.append(line.strip())\n\ntasks.remove(\"buy stamps\")\ntasks.append(\"water the plants\")\n\nwith open(\"tasks.txt\", \"w\") as file:\n    for task in tasks:\n        file.write(task + \"\\n\")\n\nwith open(\"tasks.txt\") as file:\n    print(file.read())\n```\n\n```output\nwash the car\ncall the bank\nwater the plants\n```\n\nThe order matters: read first, then write. Opening the file with `\"w\"` empties it at once, so a program that opens it for writing before reading it has nothing left to read.\n\n### Deleting a file\n\nTo delete a file completely, a program asks the operating system. Python's functions for that are in the `os` module, which a program takes into use with the line `import os` at its start (a later module tells more about modules). `os.remove(name)` deletes a file, and `os.path.exists(name)` tells whether a file exists:\n\n```python\nimport os\n\nwith open(\"draft.txt\", \"w\") as file:\n    file.write(\"Just a draft\\n\")\n\nprint(os.path.exists(\"draft.txt\"))\nos.remove(\"draft.txt\")\nprint(os.path.exists(\"draft.txt\"))\n```\n\n```output\nTrue\nFalse\n```\n\nA deleted file doesn't go to a recycle bin: it's gone. Deleting a file that doesn't exist stops the program with a `FileNotFoundError`.\n","task":"Fill in the blanks so the function `clear_file(filename)` empties the file it's given, without deleting it.\n","kind":"fill","seed":"def clear_file(filename):\n    with open(filename, [[\"w\"‖'w']]) as file:\n        [[pass]]\n\n\nif __name__ == \"__main__\":\n    clear_file(\"log.txt\")\n","solution":"def clear_file(filename):\n    with open(filename, \"w\") as file:\n        pass\n\n\nif __name__ == \"__main__\":\n    clear_file(\"log.txt\")\n","hints":["Opening a file in one of the modes empties it straight away.","The mode is `\"w\"`. The block then needs a statement that does nothing: `pass`."],"tests":[{"name":"clear_file(\"log.txt\")","stdin":"","call":"clear_file(\"log.txt\")\n","files":{"log.txt":"Started\nStopped\n"},"writes":{"log.txt":""},"expect":"","hidden":false},{"name":"clear_file(\"old.txt\")","stdin":"","call":"clear_file(\"old.txt\")\n","files":{"old.txt":"something old\n"},"writes":{"old.txt":""},"expect":"","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Write a function `remove_line(filename, text)` that removes every line that is exactly `text` from the file and keeps the other lines in their order.\n\nIf `tasks.txt` has\n\n```text\nwash the car\nbuy stamps\ncall the bank\n```\n\nthen after `remove_line(\"tasks.txt\", \"buy stamps\")` it has:\n\n```text\nwash the car\ncall the bank\n```\n","kind":"code","seed":"def remove_line(filename, text):\n    pass\n\n\nif __name__ == \"__main__\":\n    remove_line(\"tasks.txt\", \"buy stamps\")\n","solution":"def remove_line(filename, text):\n    kept = []\n    with open(filename) as file:\n        for line in file:\n            line = line.strip()\n            if line != text:\n                kept.append(line)\n\n    with open(filename, \"w\") as file:\n        for line in kept:\n            file.write(line + \"\\n\")\n\n\nif __name__ == \"__main__\":\n    remove_line(\"tasks.txt\", \"buy stamps\")\n","hints":["First read the file into a list, keeping only the stripped lines that aren't `text`.","When the reading `with` block has ended, open the same file with `\"w\"` and write each kept line back, with a line break after it."],"tests":[{"name":"remove_line(\"tasks.txt\", \"buy stamps\")","stdin":"","call":"remove_line(\"tasks.txt\", \"buy stamps\")\n","files":{"tasks.txt":"wash the car\nbuy stamps\ncall the bank\n"},"writes":{"tasks.txt":"wash the car\ncall the bank\n"},"expect":"","hidden":false},{"name":"remove_line(\"words.txt\", \"the\")","stdin":"","call":"remove_line(\"words.txt\", \"the\")\n","files":{"words.txt":"the\ncat\nsat\nthe\nend\n"},"writes":{"words.txt":"cat\nsat\nend\n"},"expect":"","hidden":true}],"require":[],"forbid":[]},{"task":"At the end of each day, the notes in a file are moved to `archive.txt`. Write a function `archive(filename)` that adds the contents of the file `filename` to the end of `archive.txt` (creating it if it's missing) and then deletes the file `filename`.\n\nIf `today.txt` has\n\n```text\nMet the plumber\n```\n\nand `archive.txt` has\n\n```text\nFixed the fence\n```\n\nthen after `archive(\"today.txt\")`, `today.txt` is gone and `archive.txt` has:\n\n```text\nFixed the fence\nMet the plumber\n```\n","kind":"code","seed":"import os\n\n\ndef archive(filename):\n    pass\n\n\nif __name__ == \"__main__\":\n    archive(\"today.txt\")\n","solution":"import os\n\n\ndef archive(filename):\n    with open(filename) as file:\n        contents = file.read()\n    with open(\"archive.txt\", \"a\") as file:\n        file.write(contents)\n    os.remove(filename)\n\n\nif __name__ == \"__main__\":\n    archive(\"today.txt\")\n","hints":["Read the whole file with `read()`, then open `archive.txt` in append mode and write what you read.","When both files are closed, delete the original with `os.remove(filename)`."],"tests":[{"name":"Archive today.txt","stdin":"","call":"archive(\"today.txt\")\nprint(\"today.txt still there:\", os.path.exists(\"today.txt\"))\n","files":{"today.txt":"Met the plumber\n","archive.txt":"Fixed the fence\n"},"writes":{"archive.txt":"Fixed the fence\nMet the plumber\n"},"expect":"today.txt still there: False","hidden":false},{"name":"No archive yet","stdin":"","call":"archive(\"monday.txt\")\nprint(\"monday.txt still there:\", os.path.exists(\"monday.txt\"))\n","files":{"monday.txt":"Painted the door\nBought nails\n"},"writes":{"archive.txt":"Painted the door\nBought nails\n"},"expect":"monday.txt still there: False","hidden":true}],"require":[],"forbid":[]}]}