I'm pretty new to python, and am wondering if there's any way to put a variable into a file name, so that you can create files with different names each time.
In my particular case, I'd like to add date and time to the file name. If it was possible, this would work perfectly:
example = open("Path/to/file%s", "w") % str(datetime.now())
...but it doesn't. Is there any way to get that sort of functionality using a different approach? I've tried searching for an answer either way using multiple phrasings, but I can't find a yea or nay on it.
Thanks in advance guys.
EDIT: That was supposed to be an open() function, adjusted accordingly.
This should work. format() will replace the placeholder {0} in the string with the formatted datetime string (datestr).
>>> from datetime import datetime
>>> datestr = datetime.strftime(datetime.today(), "%Hh %Mm %Ss %A, %B %Y")
>>> examplefile = open("/home/michael/file{0}".format(datestr), 'w')
>>> print(examplefile)
<open file '/home/michael/file21h 20m 34s Monday, September 2012', mode 'w' at 0x89fcf98>
Modifying your answer to still use the old-style % formatting, you might do:
example = open("Path/to/file%s" % datetime.now(), "w")
Note that I've called open(), which is probably what you want to do (otherwise you're just creating a tuple). Also, using the %s format specifier automatically converts the argument to a string, so you don't really need the str().
The reason your example doesn't work has nothing to do with files.
example = ("Path/to/file%s", "w") % str(datetime.now())
The above is using the % operator with a tuple on the left, and a string on the right. But the % operator is for building strings based on a string template, which appears on the left of the %. Putting a tuple on the left just doesn't make sense.
You need to break what you want to do into more basic steps. You start with "I want to open a file whose name includes the current date and time". There is no way to directly do that, which is why you couldn't find anything about it. But a filename is just a string, so you can use string operations to build a string, and then open that string. So your problem isn't really "how do I open a file with the date/time in the name?", but rather "how do I put the date/time into a string along with some other information?". You appear to already know an answer to that question: use % formatting.
This makes sense; otherwise we'd have to implement every possible string operation for files as well as for strings. And also for everything else we use strings for. That's not the way (sane) programming works; we want to be able to reuse operations that already exist, not start from scratch every time.
So what you do is use string operations (that have nothing to do with files, and neither know nor care that you're going to eventually use this string to open a file) to build your filename. Then you pass that string to the file opening function open (along with the "w" string to specify that you want it writeable).
For example:
filename = "Path/to/file%s" % datetime.now()
example = open(filename, "w")
You can put it in one line if you want:
example = open("Path/to/file%s" % datetime.now(), "w")
But if you're relatively new to programming and to Python, I recommend you keep your small steps broken out until you're more comfortable with things in general.
All the answers posted here identify the problem correctly, that is your string formatting is not correct.
You should also check that the string you end up with is actually a valid file name for the operating system you are trying to create files on.
Your example doesn't generate a valid file name on Windows, and although will work on Linux, the file name created will not be what you expect:
>>> f = open(str(datetime.datetime.now()),'w')
>>> f.write('hello\n')
>>> f.close()
>>> quit()
-rw-r--r-- 1 burhan burhan 6 Sep 11 06:53 2012-09-11 06:53:04.685335
On Windows it doesn't work at all:
>>> open(str(datetime.datetime.now()),'w')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] invalid mode ('w') or filename: '2012-09-11 06:51:26.873000'
This would be a better option (2.6+):
filename = "Path/to/file/{0.year}{0.month}{0.day}".format(datetime.now())
For older versions of Python, you can use the classic option:
filename = "Path/to/file/%s" % datetime.strftime(datetime.now(),"%Y%m%d")
Related
I'm currently working with tkinter in Python (beginner), and I'm writing a small applet that requires one of the labels to dynamically change based on what the name of a selected .csv file is, without the '.csv' tag.
I can currently get the filepath to the .csv file using askopenfilename(), which returns a string that looks something like "User/Folder1/.../filename.csv". I need some way to extract "filename" from this filepath string, and I'm a bit stuck on how to do it. Is this simply a regex problem? Or is there a way to do this using string indices? Which is the "better" way to do it? Any help would be great. Thank you.
EDIT: The reason I was wondering if regex is the right way to do it is because there could be duplicates, e.g. if the user had something like "User/Folder1/hello/hello.csv". That's why I was thinking maybe just use string indices, since the file name I need will always end at [:-4]. Am I thinking about this the right way?
Solution:
import os
file = open('/some/path/to/a/test.csv')
fname = os.path.splitext(str(file))[0].split('/')[-1]
print(fname)
# test
If you get file path and name as string, then:
import os
file = "User/Folder1/test/filename.csv"
fname = os.path.splitext(file)[0].split('/')[-1]
print(fname)
# filename
Explanation on how it works:
Pay attention that command is os.path.splitEXT, not os.path.splitTEXT - very common mistake.
The command takes argument of type string, so if we use file = open(...), then we need to pass os.path.splitext argument of type string. Therefore in our first scenario we use:
str(file)
Now, this command splits complete file path + name string into two parts:
os.path.splitext(str(file))
# result:
['/some/path/to/a/test','csv']
In our case we only need first part, so we take it by specifying list index:
os.path.splitext(str(file))[0]
# result:
'/some/path/to/a/test'
Now, since we only need file name and not the whole path, we split it by /:
os.path.splitext(str(file))[0].split('/')
# result:
['some','path','to','a','test']
And out of this we only need one last element, or in other words, first from the end:
os.path.splitext(str(file)[0].split('/')[-1]
Hope this helps.
Check for more here: Extract file name from path, no matter what the os/path format
IOError: [Errno 22] invalid mode ('w+') or filename: 'hodor_2017-05-09_14:03:38.txt'
So I was having issues creating a file where as it is "name" [delimiter] "datetime" .txt
I was looking up different bits of code such as:
Turn a string into a valid filename?
python: how to convert a string to utf-8
https://github.com/django/django/blob/master/django/utils/safestring.py
and it still seems to not work for me.
My concept is simple: given a name and content write a file with that name and that content.
My code is:
def create_json_file(name, contents):
filename = u"%s_%s.json" % (name, datetime.datetime.now().strftime("%Y/%m/%d_%H:%M:%S"))
print "%s" % filename
filename = slugify(filename)
f = open(filename, "w+")
f.write(contents)
f.close()
and as you can see i have been tweaking it. I was looking up the results that django does, which uses slugify.
My original did not have that line. Maybe there is a better way to name the file too. I think the name and datetime is pretty normal but i wasnt sure what delimiters I should be using between name and datetime etc.
For the record, I am not currently using Django because i dont have a need for the framework. I am just trying to test a way to pass in a string and a json map and turn it into a config.json file essentially.
Eventually, I will want to leverage an AJAX request from a website to do this, but that is outside the scope of this question.
Use a different separator in your filename mask:
filename = u"%s_%s.json" % (name, datetime.datetime.now().strftime("%Y_%m_%d_%H%M%S"))
The OS is trying to open 2005/04/01_5:45:04.json. Slashes aren't allowed in file/directory names.
Edit: Removed colons in response to comments.
I want to create around a 100 files on the disk with each having the names 1.txt, 2.txt and so forth. I have tried different combinations of open(str(i).txt,w+), open(i+'.txt', 'w+') but none seem to work out.
Also these files do not exist on the disk before being created by Python. How to I go about solving these issues?
To create a new string, you have to concatenate two strings:
for i in range(1, 101):
with open(str(i) + '.txt', 'w') as fobj:
# do what you want here with the file object
fobj.write('foo\n')
In case you need more complicate filenames, the str.format method can come in handy. The equivalent of the above would be: '{0}.txt'.format(i). I also think it's more readable.
As for your attempts, the first one couldn't possibly work because the .txt part would have cause Python to look for a string method named txt, which does not exist. Also the second argument of open() should be a string, so that's an error as well. In the second attempt, which was almost correct you only forgot to convert i to a string. As I said above, you cannot concatenate a number with a string.
Use
open(str(i) + ".txt", "w+")
for each i to create the file with the right number. Of course, you can also use format strings:
open("%d.txt" % i, "w+") # Old-style format strings, discouraged
or
open("{0!s}.txt".format(i), "w+") # New-style format strings from Python 2.6 onwards
Trying to figure out how to out a guessing game score plus the date & time to a text file with a new line each time, keeping the old text.
This is what I've got so far;
print('You scored %s.' % scr)
file = open("scr.txt", mode='w')
file.write('Printed string %s.\n' % scr)
This isn't working by the way - it's showing that an edit has been made to the text file but nothing is showing up in the text file - so I'm doing something wrong.
I want the text file to read 'Printed string scr recorded at date & time. As well as wanting a new line each time upon writing and keeping what has been written before.
Thanks in advance. Any help would be greatly appreciated.
You're not calling file.close() anywhere. Until you do that (or file.flush()), there is no guarantee that anything will be written to the file; it could all be sitting around in a buffer somewhere.
A better way to do this is to use a with statement, so you don't have to remember to call close.
This is explained indirectly by Reading and Writing Files in the tutorial. The reference documentation explaining it in detail is scattered around the io docs, which can be hard for a novice to understand.
Also, opening the file in 'w' mode will replace the entire file each time. You want to append to the existing file, which means you need 'a' mode. See the tutorial section Reading and Writing Files or the open documentation for more details.
Adding a new line, you've already got right, with the \n in the format string.
Finally, you can get the date and time with the datetime module. If you don't mind the default ISO date format, you can just format the datetime object as a string.
Putting it all together:
import datetime
with open("scr.txt", mode='a') as file:
file.write('Printed string %s recorded at %s.\n' %
(scr, datetime.datetime.now()))
Is this what you want?
from datetime import datetime
with open('scr.txt', 'a') as file:
file.write('Printed string %s. Recorded at: %s\n' % scr %datetime.now())
Demo:
>>> n = datetime.now()
>>> print("%s"%n)
2013-12-11 08:16:38.029267
I think what you're missing is a flush and close. Python (like many other languages) uses buffers to manage data writes and batch writes to be more efficient. Try adding this after to see if you actually get some output in your file.
file.close()
Additionally, to keep the previous data in your file, you'll want to open in append mode.
file = open("scr.txt", "a")
This way, writes will append to the end of the file instead of truncating and rewriting your scores.
I am a somewhat Python/programing newbie, and I am attempting to use a python class for the first time.
In this code I am trying to create a script to backup some files. I have 6 files in total that I want to back up regularly with this script so I thought that I would try and use the python Class to save me writing things out 6 times, and also to get practice using Classes.
In my code below I have things set up for just creating 1 instance of a class for now to test things. However, I have hit a snag. I can't seem to use the operator to assign the original filename and the back-up filename.
Is it not possible to use the operator for a filename when opening a file? Or am I doing things wrong.
class Back_up(object):
def __init__(self, file_name, back_up_file):
self.file_name = file_name
self.back_up_file = back_up_file
print "I %s and me %s" % (self.file_name, self.back_up_file)
with open('%s.txt', 'r') as f, open('{}.txt', 'w') as f2 % (self.file_name, self.back_up_file):
f_read = read(f)
f2.write(f_read)
first_back_up = Back_up("syn1_ready", "syn1_backup")
Also, line #7 is really long, any tips on how to shorten it are appreciated.
Thanks
Darren
If you just want your files backed up, may I suggest using shutil.copy()?
As for your program:
If you want to substitute in a string to build a filename, you can do it. But your code doesn't do it.
You have this:
with open('%s.txt', 'r') as f, open('{}.txt', 'w') as f2 % (self.file_name, self.back_up_file):
Try this instead:
src = "%s.txt" % self.file_name
dest = "{}.txt".format(self.back_up_file)
with open(src, "rb") as f, open(dest, "wb") as f2:
# copying code goes here
The % operator operates on a string. The .format() method call is a method on a string. Either way, you need to do the operation with the string; you can't have two with statements and then try to use these operators at the end of the with statements line.
You don't have to use explicit temp variables like I show here, but it's a good way to make the code easy to read, while greatly shortening the length of the with statements line.
Your code to copy the files will read all the file data into memory at one time. That will be fine for a small file. For a large file, you should use a loop that calls .read(CHUNK_SIZE) where CHUNK_SIZE is a maximum amount to read in a single chunk. That way if you ever back up a really large file on a computer with limited memory, it will simply work rather than filling the computer's memory and making the computer start swapping to disk.
Try simplicity :)
Your line 7 is not going to parse. Split it using intermediate variables:
source_fname = "%s.txt" % self.file_name
target_fname = "%s.txt" % self.back_up_file
with open(source_fname) as source, open(target_fname) as target:
# do your thing
Also, try hard avoiding inconsistent and overly generic attribute names, like file_name, when you have two files to operate on.
Your copy routine is not going to be very efficient, too. It tries to read the entire file into memory, then write it. If I were you I'd call rsync or something similar via popen() and feed it with proper list of files to operate on. Most probably I'd use bash for that, though Python may be fine, too.