How to use the renaming function - python

This is the error which I get:
The system cannot find the file specified: '1.jpg' -> '0.jpg'
even through i have a file named 1.jpg in the directory.
I'm making file renaming script that renames all files in the directory given with a number that increases +1 with every file.
import os
def moving_script():
directory = input("Give the directory")
xlist = os.listdir(directory)
counter = 0
for files in xlist:
os.rename(files, str(counter)+".jpg")
counter = counter + 1
moving_script()
It should be renaming all files, to "0.jpg", "1.jpg" etc

Code:
import os
def moving_script():
directory = input("Give the directory")
xlist = os.listdir(directory)
counter = 0
for files in xlist:
os.rename(os.path.join(directory, files),
os.path.join(directory, str(counter)+".jpg"))
counter = counter + 1
if __name__ == '__main__':
moving_script()
Results:
~/Documents$ touch file0 file1 file2 file3 file4
ls ~/Documents/
file0 file1 file2 file3 file4
$ python renamer.py
Give the directory'/home/suser/Documents'
$ ls ~/Documents/
0.jpg 1.jpg 2.jpg 3.jpg 4.jpg

os.listdir() will return filenames, but will not include path. Thus when you pass files to os.rename() it's looking for it in the current working directory, not the one where they are (i.e. supplied by the user).
import os
def moving_script():
directory = input("Give the directory")
counter = -1
for file_name in os.listdir(directory):
old_name = os.path.join(directory, file_name)
ext = os.path.splitext(file_name)[-1] # get the file extension
while True:
counter += 1
new_name = os.path.join(directory, '{}{}'.format(counter, ext))
if not os.path.exists(new_name):
os.rename(old_name, new_name)
break
moving_script()
note that this code detects what the file extension is. In your code you may rename a non-jpg file with .jpg extension. To avoid this you may change os.listdir(directory) to glob.glob(os.path.join(directory, *.jpg')) and it will iterate only over '*.jpg' files. Don't forget you need to import glob and also on Linux it's case-sensitive, so '*.jpg' will not return '*.JPG' files
EDIT: code updated to check if new file name already exists.

Related

Rename multiple files by removing filename prefix

I'm new to Python, I have multiple files in a folder where I need to rename those files as the the given pattern.
Example:
Folder : /Users/Usr1/Documents/FilesFolder and
File's :
0. a101.employee.txt
1. a101.department.txt
2. a101.salary.txt
I want to remove the prefix of the file till a101 and rename to empoloyee.txt/salary.txt.
Expected Output:
My try:
import os
path = '/Users/User1/Documents/FilesFolder'
files = os.listdir(path)
for index, file in enumerate(files):
os.rename(os.path.join(path, file), os.path.join(path,file.removeprefix('a101')))
But unable to get expected result.
You may use regular expression:
import os
import re
path = '/Users/User1/Documents/FilesFolder'
files = os.listdir(path)
p = ".*a101.(.+)"
for file in files:
m = re.match(p, file)
if m is not None:
file_new = m.group(1)
print(file_new)
I think this can solve your problem
import os
import glob
# directory Path
path = "/path/to/dir"
# move to directory
os.chdir(path)
# Getting all files in the directory which contains a101
files = glob.glob("*a101*")
for file in files:
splitted = file.split('.')
filename, ext = splitted[-2], splitted[-1]
new_name = f"{filename}.{ext}"
os.rename(file, new_name)
If your file name is following same pattern with 3 . then you can use this for renaming. removeprefix is introduced in python 3.9.
files = ["0. a101.employee.txt", "1. a101.department.txt" ,"2. a101.salary.txt"]
for file in files:
print(".".join(file.split(".")[-2:]))
output:
employee.txt
department.txt
salary.txt
i can suggest you:
files = ["0. a101.employee.txt", "1. a101.department.txt" ,"2. a101.salary.txt"]
for index, file in enumerate(files):
filename = file.split(".")
print(filename[2]+"."+filename[3])
I got the followingoutput:
employee.txt
department.txt
salary.txt

Renaming all files in a folder with python using specific condition

I have a folder which has files with names:
"fileX.JPG" where X = 1....N
and I want to name the files as :
"000000000X.JPG" where X=1...N
The new name of the file should have the number from the old name of the file plus the zeros. so example file names I want is:
0000000000001.jpg
0000000000011.jpg
0000000000111.jpg
etc
The file name is 13 characters long. so should have zeros accordingly.
I have not started my code. Don't know where should I start.
You can use os.rename() from the os module
for path in pathlib.Path("a_directory").iterdir():
if path.is_file():
old_name = path.stem
#original filename
old_extension = path.suffix
#original file extension
Also try this:
import os
path = '/Users/myName/Desktop/directory'
files = os.listdir(path)
for index, file in enumerate(files):
os.rename(os.path.join(path, file), os.path.join(path, ''.join([str(index), '.jpg'])))
directory = path.parent
#current file location
new_name = "text" + old_name + old_extension
path.rename(pathlib.Path(directory, new_name))
You can use os.rename.
For example:
for file in os.listdir():
# Get the number, e.g.:
old_number = file.strip("file")[1].strip(".JPG")[0]
os.rename(file, f"{old_number}.JPG")
You might have to adapt based on how your files are actually namd
import os
# Function to rename multiple files
def main():
for count, filename in enumerate(os.listdir("path-to-files")):
d = str(count).zfill(12)
dst = d + ".jpg"
src ='path-to-file'+ filename
dst ='path-to-file'+ dst
# rename() function will
# rename all the files
os.rename(src, dst)
# Driver Code
if __name__ == '__main__':
# Calling main() function
main()

renaming the extracted file from zipfile

I have lots of zipped files on a Linux server and each file includes multiple text files.
what I want is to extract some of those text files, which have the same name across zipped files and save it a folder; I am creating one folder for each zipped file and extract the text file to it. I need to add the parent zipped folder name to the end of file names and save all text files in one directory. For example, if the zipped folder was March132017.zip and I extracted holding.txt, my filename would be holding_march13207.txt.
My problem is that I am not able to change the extracted file's name.
I would appreciate if you could advise.
import os
import sys
import zipfile
os.chdir("/feeds/lipper/emaxx")
pwkwd = "/feeds/lipper/emaxx"
for item in os.listdir(pwkwd): # loop through items in dir
if item.endswith(".zip"): # check for ".zip" extension
file_name = os.path.abspath(item) # get full path of files
fh = open(file_name, "rb")
zip_ref = zipfile.ZipFile(fh)
filelist = 'ISSUERS.TXT' , 'SECMAST.TXT' , 'FUND.TXT' , 'HOLDING.TXT'
for name in filelist :
try:
outpath = "/SCRATCH/emaxx" + "/" + os.path.splitext(item)[0]
zip_ref.extract(name, outpath)
except KeyError:
{}
fh.close()
import zipfile
zipdata = zipfile.ZipFile('somefile.zip')
zipinfos = zipdata.infolist()
# iterate through each file
for zipinfo in zipinfos:
# This will do the renaming
zipinfo.filename = do_something_to(zipinfo.filename)
zipdata.extract(zipinfo)
Reference:
https://bitdrop.st0w.com/2010/07/23/python-extracting-a-file-from-a-zip-file-with-a-different-name/
Why not just read the file in question and save it yourself instead of extracting? Something like:
import os
import zipfile
source_dir = "/feeds/lipper/emaxx" # folder with zip files
target_dir = "/SCRATCH/emaxx" # folder to save the extracted files
# Are you sure your files names are capitalized in your zip files?
filelist = ['ISSUERS.TXT', 'SECMAST.TXT', 'FUND.TXT', 'HOLDING.TXT']
for item in os.listdir(source_dir): # loop through items in dir
if item.endswith(".zip"): # check for ".zip" extension
file_path = os.path.join(source_dir, item) # get zip file path
with zipfile.ZipFile(file_path) as zf: # open the zip file
for target_file in filelist: # loop through the list of files to extract
if target_file in zf.namelist(): # check if the file exists in the archive
# generate the desired output name:
target_name = os.path.splitext(target_file)[0] + "_" + os.path.splitext(file_path)[0] + ".txt"
target_path = os.path.join(target_dir, target_name) # output path
with open(target_path, "w") as f: # open the output path for writing
f.write(zf.read(target_file)) # save the contents of the file in it
# next file from the list...
# next zip file...
You could simply run a rename after each file is extracted right? os.rename should do the trick.
zip_ref.extract(name, outpath)
parent_zip = os.path.basename(os.path.dirname(outpath)) + ".zip"
new_file_name = os.path.splitext(os.path.basename(name))[0] # just the filename
new_name_path = os.path.dirname(outpath) + os.sep + new_file_name + "_" + parent_zip
os.rename(outpath, new_namepath)
For the filename, if you want it to be incremental, simply start a count and for each file, go up by on.
count = 0
for file in files:
count += 1
# ... Do our file actions
new_file_name = original_file_name + "_" + str(count)
# ...
Or if you don't care about the end name you could always use something like a uuid.
import uuid
random_name = uuid.uuid4()
outpath = '/SCRATCH/emaxx'
suffix = os.path.splitext(item)[0]
for name in filelist :
index = zip_ref.namelist().find(name)
if index != -1: # check the file exists in the zipfile
filename, ext = os.path.splitext(name)
zip_ref.filelist[index].filename = f'{filename}_{suffix}.{ext}' # rename the extracting file to the suffix file name
zip_ref.extract(zip_ref.filelist[index], outpath) # use the renamed file descriptor to extract the file
I doubt this is possible to rename file during their extraction.
What about renaming files once they are extracted ?
Relying on linux bash, you can achieve it in a one line :
os.system("find "+outpath+" -name '*.txt' -exec echo mv {} `echo {} | sed s/.txt/"+zipName+".txt/` \;")
So, first we search all txt files in the specified folder, then exec the renaming command, with the new name computed by sed.
Code not tested, i'm on windows now ^^'

Code always writes filename in the output

I am trying to find which files have not had a relevant file with a similar filename (almost) so that I can generate them. But this code writes all file names basically whereas I want it to go through the first directory, go through the files and check if they have their equivilent _details.txt in the other folder, if not write the name.
I have in folder 1 those two 11.avi and 22.avi and in folder two only 11_details.txt , so am sure i should get one filename as a result
import os,fnmatch
a = open("missing_detailss5.txt", "w")
for root, dirs, files in os.walk("1/"):
for file1 in files:
if file1.endswith(".dat"):
for root, dirs, files in os.walk("2/"):
print(str(os.path.splitext(file1)[0]) + "_details.txt")
print(files)
if not (os.path.splitext(file1)[0] + "_details.txt") in files:
print(str(os.path.splitext(file1)[0]) + "_details.txt is missing")
a.write(str(os.path.splitext(file1)[0]) + "_details.txt" + os.linesep)
a.close()
here is my debug >>>
11_details.txt
['22_details.txt']
11_details.txt is missing
22_details.txt
['22_details.txt']
22_details.txt is missing
I just corrected your code directly without writing new code, you just missed a txt extension on the comparaison if.
import os
a = open("missing_detailss4.txt", "w")
for root, dirs, files in os.walk("1/"):
for file in files:
if file.endswith(".avi"):
for root, dirs, files in os.walk("2/"):
if not (str(os.path.splitext(file)[0]) + "_details.txt") in files:
a.write(str(os.path.splitext(file)[0]) + "_details.txt" + os.linesep)
a.close()
If I read your question correctly, the files ending in "_details.txt" are supposed to be in the same (relative) directory. That is, "1/some/path/file.avi" should have a corresponding file "2/some/path/file_details.txt". If that's the case, you need not iterate twice:
import os
with open("missing_detailss5.txt", "w") as outfile:
path1 = '1/'
path2 = '2/'
allowed_extensions = ['.dat', '.avi']
for root, dirs, files in os.walk(path1):
for file1 in files:
file1, ext = os.path.splitext(file)
if ext not in allowed_extensions: continue
path2 = os.path.join(path2, os.path.relpath(os.path.join(root, file1 + '_details.txt'), path1))
if not os.path.exists(path2):
print(os.path.basename(path2) + ' is missing.')
outfile.write(os.path.basename(path2) + os.linesep)
If you don't care about which extensions to check for in the first folder, then delete allowed_extensions = ['.dat', '.avi'] and if ext not in allowed_extensions: continue lines, and change file1, ext = os.path.splitext(file) to file1 = os.path.splitext(file)[0].

Recursively append files to zip archive in python

In Python 2.7.4 on Windows, if I have a directory structure that follows:
test/foo/a.bak
test/foo/b.bak
test/foo/bar/c.bak
test/d.bak
And I use the following to add them to an existing archive such that 'd.bak' is at the root of the archive:
import zipfile
import os.path
import fnmatch
def find_files(directory, pattern):
for root, dirs, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename
if __name__=='__main__':
z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED)
for filename in find_files('test', '*.*'):
print 'Found file:', filename
z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)
z.close()
The directory of the zip file is flat. It creates the foo/ directory only if a sub-directory exists in it (If I exclude test/foo/bar/c.bak, it does not create the directory. If it is included, foo/ is created but not foo/bar/ if that makes sense), but no sub-directories or files:
foo/
a.bak
b.bak
c.bak
d.bak
Am I missing something?
The problem is that you're explicitly asking it to flatten all the paths:
z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)
If you look at the docs, the default arcname is:
the same as filename, but without a drive letter and with leading path separators removed
But you're overriding that with os.path.basename(filename). (If you don't know what basename does, it returns "the last pathname component". If you don't want just the last pathname component, don't call basename.)
If you just do z.write('test/foo/bar/c.bak'), it will create a zip entry named test/foo/bar/c.bak, but if you do z.write('test/foo/bar/c.bak', 'c.bak'), it will create a zip entry named c.bak. Since you do that for all of the entries, the whole thing ends up flattened.
I figured it out. As abarnet pointed out, I had misread the docs on zipfiles. Using the following function, I can create the correct archive name for the zip file:
def createArchName(path):
line = path
if "\\" in line:
''' windows '''
discard, val = line.split("\\", 1)
return val
else:
''' unix '''
discard, val = line.split("/", 1)
return val
For those interested, the full code is as follows:
import urllib2
import zipfile
import os.path
import fnmatch
def find_files(directory, pattern):
for root, dirs, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename
def createArchName(path):
line = path
if "\\" in line:
''' windows '''
discard, val = line.split("\\", 1)
return val
else:
''' unix '''
discard, val = line.split("/", 1)
return val
if __name__=='__main__':
if not os.path.exists("test"):
os.mkdir("test")
z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED)
for filename in find_files('test', '*.*'):
archname = createArchName(filename)
print 'Found file:', archname
z.write(filename, archname, zipfile.ZIP_DEFLATED)
z.close()

Categories