Check if a filename has multiple '.'/periods in it - python

So I'm making a website and in one of the pages you can upload images.
I didn't think of this before when making my file upload function but files are allowed to have multiple . in them, so how can I differentiate between the "real" . and the fake . to get the filename and the extension.
This is my file upload function, which isn't especially relevant but it shows how I upload the files:
def upload_files(files, extensions, path, overwrite=False, rename=None):
if not os.path.exists(path):
os.makedirs(path)
filepath = None
for file in files:
name, ext = file.filename.split('.')
if ext in extensions or extensions == '*':
if rename:
filepath = path + rename + '.' + ext if path else rename + '.' + ext
else:
filepath = path + file.filename if path else file.filename
file.save(filepath, overwrite=overwrite)
else:
raise Exception('[ FILE ISSUE ] - File Extension is not allowed.')
As you can see I am splitting the filename based on the . that is there but I now need to split it and figure out which . split pair is the actual pair for filename and extension, it also creates the issue of providing too many values for the declaration name, ext since there is a third var now at least.

Sounds like you are looking for os.path.splitext which will split your filename into a name and extension part
import os
print(os.path.splitext("./.././this.file.ext"))
# => ('./.././this.file', '.ext')

So after going through your query I thought of something which might help you.
Method-1:
If you have some pre defined extensions like jpg, png, jpeg, pdf, docx, ppt, csv, xlxd ..... you can make a list of these and use that to separate your file extension
filename = Anindya.Patro.pdf
for I in filename.split('.'):
if I in list_of_files:
Do your operation
This is a brute force kinda idea.
Method-2:
The extensions are always at the last of file name - like you don't find files like Anindya.pdf.Patro
So you can access it in two ways:
By splitting at last . only
split the filename and do filename[-1] which will give you the last word after split
l = filename.split('.')
extension = l[-1]

Related

File does not exist when data obtained from os

I'm trying to add a list of image locations into a list for each parent folder for image comparison. However when I pull the list of images from the folders with OS and then check them from the list with os.path.exists, some of the paths apparently do not exist, even though the files do exist when i manually check.
How do I fix this or work out why it is now saying the file paths do not exist? I have already tried to strip out white spaces
import os
directory = '$$$'
listFiles = os.listdir(directory)
tester = []
for entry in listFiles:
fullpath = os.path.join(directory, entry)
test = fullpath
listFiles = os.listdir(fullpath)
print(listFiles)
for n in listFiles:
fullpath = os.path.join(test,n)
fullpath = fullpath.strip()
tester.append(fullpath)
for n in range (len(tester)):
print(tester[n].strip())
print(os.path.exists(tester[n]))
break
It looks like you're trying to append all the files in the directory to the list tester, including subdirectories. If you're using os.listdir(), you need to then recursively run that on all the entries which are also dirs, perhaps by using is_dir(). But instead of writing all that by hand, just use os.walk() which already recurses folders:
directory = '$$$'
tester = []
for parent, folders, files in os.walk(directory):
for file in files:
tester.append(os.path.join(parent, file))
print(tester)
That can be shortened to:
directory = '$$$'
tester = [os.path.join(parent, file)
for parent, folders, files in os.walk(directory)
for file in files]
Note: Spaces in filenames or folders don't matter when using such functions. If you were trying to execute something on command line, then spaces matter and require quoting or escaping.
.strip() doesn't remove whitespaces everywhere, just and the beginning and the end of the string.
Try to rename your directory content removing spaces everywhere, or it's better to rename it to a short string (ex. a number)
dir = '....'
content = os.listdir(dir)
for i in range(len(content)):
path = os.path.join(dir, content[i])
# if file to number : new_path = path + '/' + i + '.' + os.path.splitext(content[i])[-1]
new_path = path.replace(' ', '')
print(path, new_path)
os.rename(path, new_path)

FileNotFoundError when trying to use os.rename

I've tried to write some code which will rename some files in a folder - essentially, they're listed as xxx_(a).bmp whereas they need to be xxx_a.bmp, where a runs from 1 to 2000.
I've used the inbuilt os.rename function to essentially swap them inside of a loop to get the right numbers, but this gives me FileNotFoundError [WinError2] the system cannot find the file specified Z:/AAA/BBB/xxx_(1).bmp' -> 'Z:/AAA/BBB/xxx_1.bmp'.
I've included the code I've written below if anyone could point me in the right direction. I've checked that I'm working in the right directory and it gives me the directory I'm expecting so I'm not sure why it can't find the files.
import os
n = 2000
folder = r"Z:/AAA/BBB/"
os.chdir(folder)
saved_path = os.getcwd()
print("CWD is" + saved_path)
for i in range(1,n):
old_file = os.path.join(folder, "xxx_(" + str(i) + ").bmp")
new_file = os.path.join(folder, "xxx_" +str(i)+ ".bmp")
os.rename(old_file, new_file)
print('renamed files')
The problem is os.rename doesn't create a new directory if the new name is a filename in a directory that does not currently exist.
In order to create the directory first, you can do the following in Python3:
os.makedirs(dirname, exist_ok=True)
In this case dirname can contain created or not-yet-created subdirectories.
As an alternative, one may use os.renames, which handles new and intermediate directories.
Try iterating files inside the directory and processing the files that meet your criteria.
from pathlib import Path
import re
folder = Path("Z:/AAA/BBB/")
for f in folder.iterdir():
if '(' in f.name:
new_name = f.stem.replace('(', '').replace(')', '')
# using regex
# new_name = re.sub('\(([^)]+)\)', r'\1', f.stem)
extension = f.suffix
new_path = f.with_name(new_name + extension)
f.rename(new_path)

Cannot find the file specified when batch renaming files in a single directory

I've created a simple script to rename my media files that have lots of weird periods and stuff in them that I have obtained and want to organize further. My script kinda works, and I will be editing it to edit the filenames further but my os.rename line throws this error:
[Windows Error: Error 2: The system cannot find the file specified.]
import os
for filename in os.listdir(directory):
fcount = filename.count('.') - 1 #to keep the period for the file extension
newname = filename.replace('.', ' ', fcount)
os.rename(filename, newname)
Does anyone know why this might be? I have a feeling that it doesn't like me trying to rename the file without including the file path?
try
os.rename(filename, directory + '/' + newname);
Triton Man has already answered your question. If his answer doesn't work I would try using absolute paths instead of relative paths.
I've done something similar before, but in order to keep any name clashes from happening I temporarily moved all the files to a subfolder. The entire process happened so fast that in Windows Explorer I never saw the subfolder get created.
Anyhow if you're interested in looking at my script It's shown below. You run the script on the command line and you should pass in as a command-line argument the directory of the jpg files you want renamed.
Here's a script I used to rename .jpg files to multiples of 10. It might be useful to look at.
'''renames pictures to multiples of ten'''
import sys, os
debug=False
try:
path = sys.argv[1]
except IndexError:
path = os.getcwd()
def toint(string):
'''changes a string to a numerical representation
string must only characters with an ordianal value between 0 and 899'''
string = str(string)
ret=''
for i in string:
ret += str(ord(i)+100) #we add 101 to make all the numbers 3 digits making it easy to seperate the numbers back out when we need to undo this operation
assert len(ret) == 3 * len(string), 'recieved an invalid character. Characters must have a ordinal value between 0-899'
return int(ret)
def compare_key(file):
file = file.lower().replace('.jpg', '').replace('dscf', '')
try:
return int(file)
except ValueError:
return toint(file)
#files are temporarily placed in a folder
#to prevent clashing filenames
i = 0
files = os.listdir(path)
files = (f for f in files if f.lower().endswith('.jpg'))
files = sorted(files, key=compare_key)
for file in files:
i += 10
if debug: print('renaming %s to %s.jpg' % (file, i))
os.renames(file, 'renaming/%s.jpg' % i)
for root, __, files in os.walk(path + '/renaming'):
for file in files:
if debug: print('moving %s to %s' % (root+'/'+file, path+'/'+file))
os.renames(root+'/'+file, path+'/'+file)
Edit: I got rid of all the jpg fluff. You could use this code to rename your files. Just change the rename_file function to get rid of the extra dots. I haven't tested this code so there is a possibility that it might not work.
import sys, os
path = sys.argv[1]
def rename_file(file):
return file
#files are temporarily placed in a folder
#to prevent clashing filenames
files = os.listdir(path)
for file in files:
os.renames(file, 'renaming/' + rename_file(file))
for root, __, files in os.walk(path + '/renaming'):
for file in files:
os.renames(root+'/'+file, path+'/'+file)
Looks like I just needed to set the default directory and it worked just fine.
folder = r"blah\blah\blah"
os.chdir(folder)
for filename in os.listdir(folder):
fcount = filename.count('.') - 1
newname = filename.replace('.', ' ', fcount)
os.rename(filename, newname)

Python: Need to use a file by name and either one of two extension

path = "/test/"
file = "afile"
path = (path + '/' + file + ('.png' or '.jpg'))
Does test have afile.jpg or afile.png and use the one it has.
I know this is incorrect, but it sums up what I would like to do.
I have a file name (file) and want to added it to path and since I'm not sure if the file is a JPG or PNG I want to try both.
Obviously the above is not going to work. But I need a simple check. My solution required listing file directories for matches. There has to be a simple solution?
Test if the file exists:
filename = os.path.join(path, file)
for extension in ('.png', '.jpg'):
if os.path.isfile(filename + extension):
filename += extension
break
else:
print 'File not found'

How To Include "part#+.rar" In "Extensions

So I'm using a script to split filenames into "name" and "extension" so I can then apply a bunch of rules to and play around with the "name" and have the script put everything back together at the end.
At the moment, I'm using:
import os, shutil, re
def rename_file (original_filename):
name, extension = os.path.splitext(original_filename)
name = re.sub(r"\'", r"", name) # etc...more of these...
new_filename = name + extension
try:
# moves files or directories (recursively)
shutil.move(original_filename, new_filename)
except shutil.Error:
print ("Couldn't rename file %(original_filename)s!" % locals())
[rename_file(f) for f in os.listdir('.') if not f.startswith('.')]
My problem is that os.path.splitext() includes "the .part(s)" of the ".partX.rar" as part of the filename, whereas I'd like it to be included as part of the file extension.
How can I get the the script to do that (without having a list of "extensions" or a completely separate script for rar files)?
Thanks!
os.path.splitext does a reverse search for '.' and returns the first match it finds. So out of the box splitext will not do what you need. If you are just using it to tokenize file names I suggest that you parse the filename yourself by splitting on . taking the left side as the name and then rejoining the right side.
Here is one way to do it:
def split_name(file_name):
'''
Returns root_filename, 'middle tokens', and extension
'''
tokens = file_name.split('.')
return (tokens[0], ".".join(tokens[1:-1]), tokens[-1]) if len(tokens) >1 else file_name
file_name = 'this.is.a.txt'
split_name(file_name)
#result is:
>>>  ('this', 'is.a', 'txt')

Categories