how do i open a file in python with variable name? - python-3.x

I am trying to open a file that has a random time date stamp as part of its name. Most of the filename is known eg filename = 2017_01_23_624.txt is my test name. The date and numbers is the part I am trying to replace with something unknown as it will change.
My question relates to opening an existing file and not creating a new filename. The filenames are created by a separate program and I must be able to open them. I also want to change them once they are open.
I have been trying to construct the filename string as follow but get invalid syntax.
filename = "testfile" + %s + ".txt"
print(filename)
fo = open(filename)

You can't open a file with a partial filename containing a wildcard for it to match. What you would have to do it look at all the files in your directory and pick the one that matches best.
Simple example:
import os
filename = "filename2017_" # known section
direc = r"directorypath"
matches = [ fname for fname in os.listdir(direc) if fname.startswith(filename) ]
print(matches)
You can however use the glob module (Thanks to bzimor) to pattern match your files. See glob docs for more info.
import glob, os
# ? - represents any single character in the filename
# * - represents any number of characters in the filename
direc = r"directorypath"
pattern = 'filename2017-??-??-*.txt'
matches = glob.glob(os.path.join(direc, pattern))
print(matches)
Similar to first solution is that you still get back a list of filenames to choose from to then open. But with the glob module you can more accurately match your files if you so need. It all depends on how tight you want it to be.

Related

copy and rename files starting at a specific integer value in python

My codes work but for a few pain points that perhaps you can help me understand. I want to copy files from one directory to another and rename them at the same time. for example:
c:\path\
octo.jpeg
novem.jpeg
decem.jpeg
to:
c:\newpath\
001.jpeg
002.jpeg
003.jpeg
The codes I wrote from a cursory google search are as follows but I'm not sure why I need the 'r' in the path variables. The 'files = os.listdir(srcPath)' line I'm sure I don't need. This will move the files and renames them using the 'count' variable in the for loop but I want to name each file starting at a specific number, say 65. Should I use the shutil library and copy2 method to first copy the files and then rename or is there an easier way?
import os
from os import path
srcPath = r'C:\Users\Talyn\Desktop\New folder\Keep\New folder'
destPath = r'C:\Users\Talyn\Desktop\New folder\Keep\hold'
#files = os.listdir(srcPath)
def main():
for count, filename in enumerate(os.listdir(srcPath)):
dst = '{:03d}'.format(count) + ".jpeg"
os.rename(os.path.join(srcPath, filename), os.path.join(destPath, dst))
if __name__=="__main__":
main()
From the official Python Docs:
Both string and bytes literals may optionally be prefixed with a letter 'r' or 'R'; such strings are called raw strings and treat backslashes as literal characters.
The r is telling python interpreter to treat the backslashes(\) in the path string as literal characters and not as escaping characters.
For naming the files from a specific number:
dst = '{:03d}'.format(count + your_number) + ".jpeg"
Using copyfile from shutil
copyfile(srcPath + filename, destPath + dst)

What is the appropriate way to take in files that have a filename with a timestamp in it?

What is the appropriate way to take in files that have a filename with a timestamp in it and read properly?
One way I'm thinking of so far is to take these filenames into one single text file to read all at once.
For example, filenames such as
1573449076_1570501819_file1.txt
1573449076_1570501819_file2.txt
1573449076_1570501819_file3.txt
Go into a file named filenames.txt
Then something like
with open('/Documents/filenames.txt', 'r') as f:
for item in f:
if item.is_file():
file_stat = os.stat(item)
item = item.replace('\n', '')
print("Fetching {}".format(convert_times(file_stat)))
My question is how would I go about this where I can properly read the names in the text file given that they have timestamps in the actual names? Once figuring that out I can convert them.
If you just want to get the timestamps from the file names, assuming that they all use the same naming convention, you can do so like this:
import glob
import os
from datetime import datetime
# Grab all .txt files in the specified directory
files = glob.glob("<path_to_dir>/*.txt")
for file in files:
file = os.path.basename(file)
# Check that it contains an underscore
if not '_' in file:
continue
# Split the file name using the underscore as the delimiter
stamps = file.split('_')
# Convert the epoch to a legible string
start = datetime.fromtimestamp(int(stamps[0])).strftime("%c")
end = datetime.fromtimestamp(int(stamps[1])).strftime("%c")
# Consume the data
print(f"{start} - {end}")
...
You'll want to add some error checking and handling; for instance, if the first or second index in the stamps array isn't a parsable int, this will fail.

How do I dynamically create a variable name in a loop to assign to a file name in python 3

I'm still relatively new to programming and Python. But I am sure this must be possible but my searches are not turning up what I'm looking for.
In my current directory, I have 6 PDF files that I wish to read in via the loop below.
What I would like to do is open each of the PDF's with a new variable name, as you can see it is imaginatively called pdf[1-6]File.pdf.
I can list the files in the console and pull them via the code when I stick breaks in to stop it executing but I can't for the life of me work out how to create the variable name. I thought something like "pdf" + str(i) + "File" would have worked but I'm missing something.
Code is below - not complete but enough so you get what I'm looking at:
#Open the PDF files in the current directory for
#reading in binary mode
def opensource():
listOfFiles = os.listdir('.')
pattern = "*.pdf"
for entry in listOfFiles:
if fnmatch.fnmatch(entry, pattern):
# Works to here perfectly
for i in range(len(entry)):
# print(len(entry))
# Trying to create the variable name with
# an incremental numeral in the file name
"pdf" + i + "File" = open(entry, 'rb')
This bit below is how I'm currently doing it and its a pain in the backside. I'm sure it can be done programmatically
#This is the old way. Monolithic and horrid
#Open the files that have to be merged one by one
pdf1File = open('file1.pdf', 'rb')
pdf2File = open('file2.pdf', 'rb')
pdf3File = open('file3.pdf', 'rb')
pdf4File = open('file4.pdf', 'rb')
pdf5File = open('file5.pdf', 'rb')
pdf6File = open('file6.pdf', 'rb')
All help gratefully received.
Thanks
If you are going to use the file pointer outside this for loop, you can very well use a dictionary to do that..
def opensource():
listOfFiles = os.listdir('.')
pattern = "*.pdf"
file_ptrs = {}
for entry in listOfFiles:
if fnmatch.fnmatch(entry, pattern):
# Works to here perfectly
for i in range(len(entry)):
# print(len(entry))
# Trying to create the variable name with
# an incremental numeral in the file name
file_ptrs["pdf" + str(i) + "File"] = open(entry, 'rb')
Caution: Its always advisable to use the open method alongside of a "with" clause in python.. it takes care of closing the file once the file operation goes out of context.

how do i manipulate the path name so it doesn't print out the entire name

I'm new to programming. i need to index three separate txt files. And do a search from an input. When i do a print it gives me the entire path name. i would like to print the txt file name.
i've trying using os.list in the function
import os
import time
import string
import os.path
import sys
word_occurrences= {}
def index_text_file (txt_filename,ind_filename, delimiter_chars=",.;:!?"):
try:
txt_fil = open(txt_filename, "r")
fileString = txt_fil.read()
for word in fileString.split():
if word in word_occurrences:
word_occurrences[word] += 1
else:#
word_occurrences [word] = 1
word_keys = word_occurrences.keys()
print ("{} unique words found in".format(len(word_keys)),txt_filename)
word_keys = word_occurrences.keys()
sorted(word_keys)
except IOError as ioe: #if the file can't be opened
sys.stderr.write ("Caught IOError:"+ repr(ioe) + "/n")
sys.exit (1)
index_text_file("/Users/z007881/Documents/ABooks_search/CODE/booksearch/book3.txt","/Users/z007881/Documents/ABooks_search/CODE/booksearch/book3.idx")
SyntaxError: invalid syntax
(base) 8c85908188d1:CODE z007881$ python3 indexed.py
9395 unique words found in /Users/z007881/Documents/ABooks_search/CODE/booksearch/book3.t
xt
i would like it to say 9395 unique words found in book3.txt
One way to do it would be to split the path on the directory separator / and pick the last element:
file_name = txt_filename.split("/")[-1]
# ...
# Then:
print("{} unique words found in".format(len(word_keys)), file_name)
# I would prefer using an fstring, unless your Python version is too old:
print(f"{len(word_keys)} found in {file_name}")
I strongly advise to change the name of txt_filename into something less misleading like txt_filepath, since it does not contain a file name but a whole path (including, but not limited to, the file name).

Python: read a string and use it to rename the file

I'm completely new to python and I'm trying to rename a set of files using a string on a specific line within the file and use it to rename the file. Such string is found at the same line in each file.
As an example:
10 files in the same path
the string is found in line number 14 and it starts at character number 40 and it is 50 characters in length
Then use the extracted string to rename the respective file
I'm trying to use this code, but I fail to figure out how to get it working:
for filename in os.listdir(path):
if filename.startswith("out"):
with open(filename) as openfile:
fourteenline = linecache.getline(path, 14)
os.rename(filename, fourteenline.strip())
Take care providing the full path to the file, in case your not allready working in this folder (use os.path.join()). Furthermore, when using linecache, you dont need to open the file.
import os, linecache
for filename in os.listdir(path):
if not filename.startswith("out"): continue # less deep
file_path = os.path.join(path, filename) # folderpath + filename
fourteenline = linecache.getline(file_path, 14) # maybe 13 for 0-based index?
new_file_name = fourteenline[40:40+50].rstrip() # staring at 40 with length of 50
os.rename(file_path, os.path.join(path, new_file_name))
useful ressources:
Reading specific lines only (Python)
Understanding Python's slice notation
How to rename a file using Python
python docs - string.strip()

Resources