Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am trying to write a block of code which opens a new file every time a Python3 script is run.

I am constructing the filename using an incrementing number.

For example, the following are some examples of valid filenames which should be produced:

output_0.csv
output_1.csv
output_2.csv
output_3.csv

On the next run of the script, the next filename to be used should be output_4.csv.

In C/C++ I would do this in the following way:

  • Enter an infinite loop
  • Try to open the first filename, in "read" mode
  • If the file is open, increment the filename number and repeat
  • If the file is not open, break out of the loop and re-open the file in "write" mode
  • This doesn't seem to work in Python 3, as opening a non-existing file in read mode causes an exception to be raised.

    One possible solution might be to move the open file code block inside a try-catch block. But this doesn't seem like a particularly elegant solution.

    Here is what I tried so far in code

    # open a file to store output data
    filename_base = "output"
    filename_ext = "csv"
    filename_number = 0
    while True:
        filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
        with open(filename_full, "r") as f:
            if f.closed:
                print(f"Writing data to {filename_full}")
                break
            else:
                print(f"File {filename_full} exists")
                filename_number += 1
    with open(filename_full, "w") as f:
    

    As explained above this code crashes when trying to open a file which does not exist in "read" mode.

    The exception is there to inform you "If the file is not open". Catching the exception is how you check it. There is nothing inelegant about this. – MisterMiyagi Jul 9, 2021 at 12:27

    Using pathlib you can check with Path.is_file() which returns True when it encounters a file or a symbolic link to a file.

    from pathlib import Path
    filename_base = "output"
    filename_ext = "csv"
    filename_number = 0
    filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
    p = Path(filename_full)
    while p.is_file() or p.is_dir():
        filename_number += 1
        p = Path(f"{filename_base}_{filename_number}.{filename_ext}")
    

    This loop should exit when the file isn’t there so you can open it for writing.

    A nice solution. I see only one potential issue, which is where something, like a directory, exists, and is not a file. Is there a version of this which uses something in place of is_file() to detect the presence of any path, rather than just files. (Simlinks, dirs, etc) – FreelanceConsultant Jul 9, 2021 at 12:52 is_file() will return True for symbolic links, I've updated the answer a little to account for directories – Alex Jul 9, 2021 at 13:09

    You could use the OS module to check if the file path is a file, and then open it:

    import os
    file_path = './file.csv'
    if(os.path.isfile(file_path)):
        with open(file_path, "r") as f:
        filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
          with open(filename_full, "r") as f:
              print(f"File {filename_full} exists")
              filename_number += 1
        except FileNotFoundError:
          print("Creating new file")
          open(filename_full, 'w');
          break;
    

    You might os.path.exists to check if file already exists for example

    import os
    print(os.path.exists("output_0.csv"))
    

    or harness fact that your names

    output_0.csv
    output_1.csv
    output_2.csv
    output_3.csv
    

    are so regular, exploit glob.glob like so

    import glob
    existing = glob.glob("output_*.csv")
    print(existing)  # list of existing files