0

My application offers the ability to the user to export its results. My application exports text files with name Exp_Text_1, Exp_Text_2 etc. I want it so that if a file with the same file name pre-exists in Desktop then to start counting from this number upwards. For example if a file with name Exp_Text_3 is already in Desktop, then I want the file to be created to have the name Exp_Text_4.

This is my code:

if len(str(self.Output_Box.get("1.0", "end"))) == 1:
            self.User_Line_Text.set("Nothing to export!")
        else:
            import os.path

            self.txt_file_num = self.txt_file_num + 1
            file_name = os.path.join(os.path.expanduser("~"), "Desktop", "Exp_Txt" + "_" + str(self.txt_file_num) + ".txt")

            file = open(file_name, "a")
            file.write(self.Output_Box.get("1.0", "end"))
            file.close()

            self.User_Line_Text.set("A text file has been exported to Desktop!")
Don Cruickshank
  • 5,641
  • 6
  • 48
  • 48

1 Answers1

1

you likely want os.path.exists:

>>> import os
>>> help(os.path.exists)
Help on function exists in module genericpath:

exists(path)
    Test whether a path exists.  Returns False for broken symbolic links

a very basic example would be create a file name with a formatting mark to insert the number for multiple checks:

import os

name_to_format = os.path.join(os.path.expanduser("~"), "Desktop", "Exp_Txt_{}.txt")
#the "{}" is a formatting mark so we can do file_name.format(num)

num = 1
while os.path.exists(name_to_format.format(num)):
    num+=1

new_file_name = name_to_format.format(num)

this would check each filename starting with Exp_Txt_1.txt then Exp_Txt_2.txt etc. until it finds one that does not exist.

However the format mark may cause a problem if curly brackets {} are part of the rest of the path, so it may be preferable to do something like this:

import os

def get_file_name(num):
    return os.path.join(os.path.expanduser("~"), "Desktop", "Exp_Txt_" + str(num) + ".txt")

num = 1
while os.path.exists(get_file_name(num)):
    num+=1

new_file_name = get_file_name(num)

EDIT: answer to why don't we need get_file_name function in first example?

First off if you are unfamiliar with str.format you may want to look at Python doc - common string operations and/or this simple example:

text = "Hello {}, my name is {}."
x = text.format("Kotropoulos","Tadhg")
print(x)
print(text)

The path string is figured out with this line:

 name_to_format = os.path.join(os.path.expanduser("~"), "Desktop", "Exp_Txt_{}.txt")

But it has {} in the place of the desired number. (since we don't know what the number should be at this point) so if the path was for example:

 name_to_format = "/Users/Tadhg/Desktop/Exp_Txt_{}.txt"

then we can insert a number with:

print(name_to_format.format(1))
print(name_to_format.format(2))

and this does not change name_to_format since str objects are Immutable so the .format returns a new string without modifying name_to_format. However we would run into a problem if out path was something like these:

 name_to_format = "/Users/Bob{Cat}/Desktop/Exp_Txt_{}.txt"
 #or
 name_to_format = "/Users/Bobcat{}/Desktop/Exp_Txt_{}.txt"
 #or
 name_to_format = "/Users/Smiley{:/Desktop/Exp_Txt_{}.txt"

Since the formatting mark we want to use is no longer the only curly brackets and we can get a variety of errors:

 KeyError: 'Cat'
 IndexError: tuple index out of range
 ValueError: unmatched '{' in format spec

So you only want to rely on str.format when you know it is safe to use. Hope this helps, have fun coding!

Community
  • 1
  • 1
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59