Changing directory and renaming issues - python

What I'm hoping to accomplish is to scan all the files in the specified directory and remove the numbers that is contained in the name. The problem is I can't change the directory with the code that is below.
I'm currently in the Udacity Full Stack Nanodegree Program so if anyone can help me out that is also in the program that would be a plus.
Here is the code:
import os
def rename_files():
#(1) Get file names from a folder
file_list = os.listdir("/Users/bill/Documents/web/LocalServer/prank")
#print (file_list)
saved_path = os.getcwd()
print("Our current working directory is " + saved_path)
os.chdir('/Users/bill/Documents/web/LocalServer/prank')
print("Our current working directory is ", saved_path)
#(2) For each file, rename filename
for file_name in file_list:
#print("Old Name - " + file_name)
#print("New Name - " + file_name.translate("0123457689"))
os.rename(file_name, file_name.translate("0123457689"))
os.chdir(saved_path)
print("Our current working directory is ", saved_path)
rename_files()
Here is the output I get:
Our current working directory is /Users/bill/Documents/web/LocalServer
Our current working directory is /Users/bill/Documents/web/LocalServer
Our current working directory is /Users/bill/Documents/web/LocalServer
Update 1:
I've finally changed directories but I still can't rename files. (Ex: 68chicago.jpg to chicago.jpg)
Here is my current code:
import os
def rename_files():
#(1) Get file names from a folder
file_list = os.listdir("/Users/bill/Documents/web/LocalServer/prank")
#print (file_list)
saved_path = os.getcwd()
print("Our current working directory is " + saved_path)
os.chdir('/Users/bill/Documents/web/LocalServer/prank')
new_path = os.getcwd()
print("Our current working directory is ", new_path)
#(2) For each file, rename filename
for file_name in file_list:
#print("Old Name - " + file_name)
#print("New Name - " + file_name.translate("0123457689"))
os.rename(file_name, file_name.translate("0123457689"))
print("Our current working directory is ", new_path)
rename_files()
Here is my current output:
Our current working directory is /Users/bill/Documents/web/LocalServer
Our current working directory is /Users/bill/Documents/web/LocalServer/prank
Our current working directory is /Users/bill/Documents/web/LocalServer/prank
Update 2:
I've finally solved the problem thanks to #Dan.
Here is his code:
import os
def rename_files():
#(1) Get file names from a folder
file_list = os.listdir("/Users/bill/Documents/web/LocalServer/prank")
#print (file_list)
saved_path = os.getcwd()
print("Our current working directory is " + saved_path)
os.chdir('/Users/bill/Documents/web/LocalServer/prank')
new_path = os.getcwd()
print("Our current working directory is ", new_path)
#(2) For each file, rename filename
for file_name in file_list:
#print("Old Name - " + file_name)
#print("New Name - " + file_name.translate("0123457689"))
os.rename(file_name, ''.join([i for i in file_name if not i.isdigit()])) # This works on my machine
os.chdir(saved_path)
print("Our current working directory is ", saved_path)
rename_files()

It looks like you want to change to a dir and then change back to the first directory? If that's the case you want something like this:
import os
def rename_files():
#(1) Get file names from a folder
file_list = os.listdir("/Users/bill/Documents/web/LocalServer/prank")
#print (file_list)
saved_path = os.getcwd()
print("Our current working directory is " + saved_path)
os.chdir('/Users/bill/Documents/web/LocalServer/prank')
new_path = os.getcwd()
print("Our current working directory is ", new_path)
#(2) For each file, rename filename
for file_name in file_list:
#print("Old Name - " + file_name)
#print("New Name - " + file_name.translate("0123457689"))
os.rename(file_name, ''.join([i for i in file_name if not i.isdigit()])) # This works on my machine
os.chdir(saved_path)
print("Our current working directory is ", saved_path)
rename_files()

Your problem is that you use .translate() incorrectly. It does not change the file names at all, so rename actually renames X into X:
'68chicago.jpg'.translate('0123457689')
# '68chicago.jpg'
Try using list comprehension:
def clean_name(name):
return ''.join(x for x in name if not x.isdigit())
# 'chicago.jpg'

Here's a version that doesn't require changing the current directory. Just specify the directory where files are to be renamed. If you specify the full path to the old and new name changing the directory isn't required.
This also shows how to use translate properly. maketrans takes one, two, or three parameters (see docs). The three-parameter version takes two strings of equal length for 1:1 translating, plus a third parameter of characters to delete. It returns a dictionary suitable to be used with translate.
import os
def rename_files(directory):
xlat = str.maketrans('','','0123457689')
file_list = os.listdir(directory)
for file_name in file_list:
old_name = os.path.join(directory,file_name)
new_name = os.path.join(directory,file_name.translate(xlat))
os.rename(old_name,new_name)
rename_files('/Users/bill/Documents/web/LocalServer/prank')

The primary problem is your code isn't using the str.translate() method in the proper manner—your need to pass it a translation table for it to work.
This following works and avoids renaming files that don't need to be (i.e. doesn't rename them to their current name). This takes a little extra processing, but is probably faster that performing a useless OS-level operation.
Note: A more robust solution would also need to handle any exceptions the os.rename() call might raise—which definitely could occur for a number of reasons.
For example:
Perhaps a file with the translated name already exists.
All the characters of the original file get removed, so the new file name is the empty string.
File permissions or attribute prevent renaming.
etc.
The code:
from contextlib import contextmanager
import string
import os
#contextmanager
def temp_cd(path):
"""Temporarily change the current directory to path, yield, then restore it."""
saved_path = os.getcwd()
yield
os.chdir(saved_path)
def rename_files(path):
TRANS_TABLE = str.maketrans(dict.fromkeys(string.digits))
with temp_cd(path):
for file_name in os.listdir(path):
if any(ch in file_name for ch in string.digits):
# os.rename(file_name, file_name.translate(TRANS_TABLE))
print(file_name, '->', file_name.translate(TRANS_TABLE))
rename_files("/Users/bill/Documents/web/LocalServer/prank")

Related

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)

Moving folders to a directory according to their name

I'm new in Python and am currently developing an application that moves folders to a specific directory according their folder name.
I get no errors nor warnings but the application won't move the folders.
Here's the code:
import os
import shutil
def shorting_algorithm():
file_list = []
directory = input("Give the directory you want to search.")
newdir = "D:\\Torrents\\Complete\\Udemy"
name = "'" + input("Give the name of the files you want to move.") + "'"
xlist = os.listdir(directory)
print(xlist)
print(name)
for files in xlist:
if name in files:
shutil.move(directory + files,newdir)
shorting_algorithm()
Note: I tried removing "'" +...+"'" but it didn't work either. Any ideas?
Don't forget the file separator while joining the file and the directory.
for files in xlist:
#if name in files: EDIT: As pointed out by IosiG, Change here too
if name == files:
shutil.move(directory + files,newdir) #make changes here
directory + '\\' + files.
#or
import os
os.path.join(directory,files)
You don't need the for loop or the if statement. You already identified the file in the main code block. Since you are specifying a directory and a filename explicitly, you don't need to do a loop through a directory list to find one. That's more for when you want a program to automatically find a file that fits some particular condition. Try this:
import os
import shutil
def shorting_algorithm():
directory = input("Give the directory you want to search.")
newdir = r'D:\Torrents\Complete\Udemy'
name = "\\" + input("Give the name of you files you want to move.")
print(name)
print(directory)
shutil.move(directory + name,newdir)
shorting_algorithm()
Getting rid of the extra quotes and adding your slashes to the path, turning your newdir into a raw string to avoid escapes, and getting rid of the for loop should make this code work. I just tested it out and it works here.
The problem is your loop, you mixed two ways of iterating.
What happens is the following:
for files in xlist: #loop through the names of the files
if name in files: # look for the name of your file inside the name of another file
shutil.move(directory + files,newdir)
What should be done is the following:
if name in xlist:
shutil.move(directory + name,newdir)
or also
for file in xlist: # only reason for this is if you want input check
if str(file) == name:
# do whatever you need
Also, you have to remove the "'" +...+"'" from the input, since you are entering those into the string, which will make the comparison quite messy.
I'd recommend also to use raw_input instead of input.
Thank you all for your answers, the problem was easily solved by using "shutil.move(directory + '\' + files,newdir)" as suggested.
import os
import shutil
def shorting_algorithm():
directory = input("Give the directory you want to search.")
name = input("Give the name of you files you want to move.")
newdir = input("Give the new directory.")
xlist = os.listdir(directory)
for files in xlist:
if name in files:
shutil.move(directory + '\\' + files,newdir)
shorting_algorithm()

My Python script ignores files while copying

Basically what I want to do in my script is copy some files from dest_path to source_path. You can set it up and see how it works -
But for some reason it copies the first file and tells me that the rest is already copied, which is not true. Is there something that I'm not seeing or that I did wrong? im pretty new to python so sorry if I did something obviously wrong, I just cant see it...
import time, shutil, os, datetime
source_path = r"C:\SOURCE" # Your Source path
dest_path = r"C:\DESTINATION" # Destination path
file_ending = '.txt' # Needed File ending
files = os.listdir(source_path) # defines
date = datetime.datetime.now().strftime('%d.%m.%Y') # get the current date
while True:
print("Beginning checkup")
print("=================")
if not os.path.exists(source_path or dest_path): # checks if directory exists
print("Destination/Source Path does not exist!")
else:
print("Destination exists, checking files...")
for f in files:
if f.endswith(file_ending):
new_path = os.path.join(dest_path, date, )
src_path = os.path.join(source_path, f)
if not os.path.exists(new_path): # create the folders if they dont already exists
print("copying " + src_path)
os.makedirs(new_path)
shutil.copy(src_path, new_path)
else:
print( src_path + " already copied")
# shutil.copy(src_path, new_path)
print("=================")
print('Checkup done, waiting for next round...')
time.sleep(10) # wait a few seconds between looking at the directory
Like #user2357112 mentioned if not os.path.exists(source_path or dest_path) is not doing what you think. Change to
if not os.path.exists(source_path) or not os.path.exists(dest_path):
This will only copy one file because it creates the directory new_path the first time through in the if. Something like this should work:
if f.endswith(file_ending):
new_path = os.path.join(dest_path, date, )
src_path = os.path.join(source_path, f)
if not os.path.exists(new_path): # create the folders if they dont already exists
os.makedirs(new_path)
if not os.path.exists(os.path.join(new_path,f)):
print("copying " + src_path)
shutil.copy(src_path, os.path.join(new_path,f))
else:
print( src_path + " already copied")
If the new_path directory doesn't exist then make the directory (this should only happen once and this if could be moved outside of the loop as well as new_path initialization). In a separate if check if the file exists inside that directory and if not copy the file to the location, else print your message.

Moving files and creating directories if certain file type in python

This is probably a simple question, but I'm brand new to python and programming in general.
I'm working on a simple program to copy/move .mp3 files from on location to another while mirroring the directory structure of the source location. What I have so far works, however it also creates new folders in the destination location even if the source folder contained no mp3 files. I only want to create the new directories if the source contains .mp3s, otherwise it could lead to a bunch of empty folders in the destination.
Here is what I have so far:
import os
import shutil #Used for copying files
##CONFIG
source_dir = "C:\Users\username\Desktop\iTunes\\" #set the root folder that you want to scan and move files from. This script will scan recursively.
destPath = "C:\Users\username\Desktop\converted From iTunes" #set the destination root that you want to move files to. Any non-existing sub directories will be created.
ext = ".mp3" #set the type of file you want to search for.
count = 0 #initialize counter variable to count number of files moved
##
##FIND FILES
for dirName, subdirList, fileList in os.walk(source_dir):
#set the path for the destination folder(s)
dest = destPath + dirName.replace(source_dir, '\\')
#if the source directory doesn't exist in the destination folder
#then create a new folder
if not os.path.isdir(dest):
os.mkdir(dest)
print('Directory created at: ' + dest)
for fname in fileList:
if fname.endswith(ext) :
#determine source & new file locations
oldLoc = dirName + '\\' + fname
newLoc = dest + '\\' + fname
if os.path.isfile(newLoc): # check to see if the file already exists. If it does print out a message saying so.
print ('file "' + newLoc + fname + '" already exists')
if not os.path.isfile(newLoc): #if the file doesnt exist then copy it and print out confirmation that is was copied/moved
try:
shutil.move(oldLoc, newLoc)
print('File ' + fname + ' copied.')
count = count + 1
except IOError:
print('There was an error copying the file: "' + fname + '"')
print 'error'
print "\n"
print str(count) + " files were moved."
print "\n"
so if the folder structure is something like:
root->
band 1->
album name->
song.m4a,
song2.m4a
right now it will create all those folders in the destination driectory, even though there are no .mp3s to copy.....
Any help is appreciated!
I think I would create my own wrapper around copy for this sort of thing:
def fcopy(src,dest):
"""
Copy file from source to dest. dest can include an absolute or relative path
If the path doesn't exist, it gets created
"""
dest_dir = os.path.dirname(dest)
try:
os.makedirs(dest_dir)
except os.error as e:
pass #Assume it exists. This could fail if you don't have permissions, etc...
shutil.copy(src,dest)
Now you can just walk the tree calling this function on any .mp3 file.
The simplest thing to do I can think of for your existing code would be to just make it skip over any folders that don't have any .mp3 files in them. This can easily be done by adding the following items and if statement to the top of your loop. The itertools.ifilter() and fnmatch.fnmatch() functions can be used together to simplify checking for files with the proper extension.
from itertools import ifilter
from fnmatch import fnmatch
ext = '.mp3'
fnPattern = '*'+ext
for dirName, subdirList, fileList in os.walk(source_dir):
if not any(ifilter(lambda fname: fnmatch(fname, fnPattern), fileList)):
print ' skipping "{}"'.format(dirName)
continue
...
You will also have to change the os.mkdir(dest) to os.makedirs(dest) in the code further down to ensure that any subdirectories skipped by earlier iterations get created when there's a need to copy files to a corresponding subbranch of the destination directory.
You could optimize things a bit by creating and saving a possibly empty iterator of matching files that have the extension, and then use it again later to to determine what files to copy:
from itertools import ifilter
from fnmatch import fnmatch
ext = '.mp3'
fnPattern = '*'+ext
for dirName, subdirList, fileList in os.walk(source_dir):
# generate list of files in directory with desired extension
matches = ifilter(lambda fname: fnmatch(fname, fnPattern), fileList)
# skip subdirectory if it does not contain any files of interest
if not matches:
continue
...
... create destination directory with os.makedirs()
...
# copy each file to destination directory
for fname in matches:
... copy file
Would shutils.copytree not do what you want in fewer lines?

Writing to a new directory in Python without changing directory

Currently, I have the following code...
file_name = content.split('=')[1].replace('"', '') #file, gotten previously
fileName = "/" + self.feed + "/" + self.address + "/" + file_name #add folders
output = open(file_name, 'wb')
output.write(url.read())
output.close()
My goal is to have python write the file (under file_name) to a file in the "address" folder in the "feed" folder in the current directory (IE, where the python script is saved)
I've looked into the os module, but I don't want to change my current directory and these directories do not already exist.
First, I'm not 100% confident I understand the question, so let me state my assumption:
1) You want to write to a file in a directory that doesn't exist yet.
2) The path is relative (to the current directory).
3) You don't want to change the current directory.
So, given that:
Check out these two functions: os.makedirs and os.path.join. Since you want to specify a relative path (with respect to the current directory) you don't want to add the initial "/".
dir_path = os.path.join(self.feed, self.address) # will return 'feed/address'
os.makedirs(dir_path) # create directory [current_path]/feed/address
output = open(os.path.join(dir_path, file_name), 'wb')
This will create the file feed/address/file.txt in the same directory as the current script:
import os
file_name = 'file.txt'
script_dir = os.path.dirname(os.path.abspath(__file__))
dest_dir = os.path.join(script_dir, 'feed', 'address')
try:
os.makedirs(dest_dir)
except OSError:
pass # already exists
path = os.path.join(dest_dir, file_name)
with open(path, 'wb') as stream:
stream.write('foo\n')
Commands like os.mkdir don't actually require that you make the folder in your current directory; you can put a relative or absolute path.
os.mkdir('../new_dir')
os.mkdir('/home/you/Desktop/stuff')
I don't know of a way to both recursively create the folders and open the file besides writing such a function yourself - here's approximately the code in-line. os.makedirs will get you most of the way there; using the same mysterious self object you haven't shown us:
dir = "/" + self.feed + "/" + self.address + "/"
os.makedirs(dir)
output = open(os.path.join(dir, file_name), 'wb')

Categories