How does one rename multiple files using python? - python

I have lots of programming experience but this is my first python script. I am trying to add the prefix "00" to all the files in a specific folder. First I read the names of all the files and save them in an array. Then I sort through the array and add the prefix "00" then use the os.rename function but somewhere along the way I've messed up something.
import sys, os
file_list = []
for file in os.listdir(sys.argv[1]):
file_list.append(file)
for i in file_list:
file_list[i] = prevName
newName = '00' + file_list[i]
os.rename(prevName, newName)
I have a .py file in the folder with all the files I want to rename. The .py file contains the script above. When i double click the .py file a cmd window flashes and disappears and none of the file names have been changed. Any help would be appreciated, sorry if this is a very obvious mistake, my python level is quite n00b at the moment.

In addition to the answer by #Padraic, also make following changes to your code.
import sys, os
file_list = []
for f in os.listdir(sys.argv[1]):
file_list.append(f)
for i in range(len(file_list)):
prevName = file_list[i]
if prevName != 'stackoverflow.py': # Mention .py file so that it doesnt get renamed
newName = '00' + file_list[i]
os.rename(prevName, newName)

Check your indentation. The second for loop is not indented correctly.
for i in file_list:
file_list[i] = prevName
You are not iterating correctly. for loops in Python are like foreach loops you may know from other programming languages. i in for i in file_list actually gives you the list's elements, so you should be doing
for i in range(len(file_list)):
file_list[i] = ......
although it is not very pythonic nor generally a good idea to modify the collection that you're currently iterating over.

Your code errors because you provide no args so sys.argv[1] would give an IndexError, you would need to call the script with the dir name from a cmd prompt not double click it:
python your_script directory <- argv[1]
Or change the code and specify the path, you also need to join the path to the filename.
path = "full_path"
for f in os.listdir(path):
curr,new = os.path.join(path,f), os.path.join(path,"00{}".format(f))
os.rename(curr,new)
os.listdir returns a list so just iterate over that, you don't need to create a list and append to it.
for i in file_list: would also make each i a filename not an index so that would cause another error but as above you don't need to do it anyway.

Related

Python makes additional folder

I have a simple question, but cant really solve that. I have the following code in groupby loop. for each file, python makes the folders \user\Desktop\CO\Sites on my destination folder, but I just want to find the path and put my zip file on that path, not making that again.
Can you please advise?
for n,g in groupby:
csv=g.to_csv(index=False)
filename = '{}{}'.format(r'C:/Users/Desktop/CO/Sites/Site_',n)
os.chdir(r'C:\Users\Desktop')
filename_csv = filename + '_Co_'+ '.csv'
filename_zip = filename + '_Co_' +'.zip'
with open(filename_csv,'w') as out_file:
out_file.write(csv)
zip_all_zips.append(filename_zip)
zip_all_csvs.append(filename_csv)
Maybe you can check if the directory is present, otherwise create it:
if not os.path.exists("filepath/"):

Python Delete Files in Directory from list in Text file

I've searched through many answers on deleting multiple files based on certain parameters (e.g. all txt files). Unfortunately, I haven't seen anything where one has a longish list of files saved to a .txt (or .csv) file and wants to use that list to delete files from the working directory.
I have my current working directory set to where the .txt file is (text file with list of files for deletion, one on each row) as well as the ~4000 .xlsx files. Of the xlsx files, there are ~3000 I want to delete (listed in the .txt file).
This is what I have done so far:
import os
path = "c:\\Users\\SFMe\\Desktop\\DeleteFolder"
os.chdir(path)
list = open('DeleteFiles.txt')
for f in list:
os.remove(f)
This gives me the error:
OSError: [WinError 123] The filename, directory name, or volume label syntax is incorrect: 'Test1.xlsx\n'
I feel like I'm missing something simple. Any help would be greatly appreciated!
Thanks
Strip ending '\n' from each line read from the text file;
Make absolute path by joining path with the file name;
Do not overwrite Python types (i.e., in you case list);
Close the text file or use with open('DeleteFiles.txt') as flist.
EDIT: Actually, upon looking at your code, due to os.chdir(path), second point may not be necessary.
import os
path = "c:\\Users\\SFMe\\Desktop\\DeleteFolder"
os.chdir(path)
flist = open('DeleteFiles.txt')
for f in flist:
fname = f.rstrip() # or depending on situation: f.rstrip('\n')
# or, if you get rid of os.chdir(path) above,
# fname = os.path.join(path, f.rstrip())
if os.path.isfile(fname): # this makes the code more robust
os.remove(fname)
# also, don't forget to close the text file:
flist.close()
As Henry Yik pointed in the commentary, you need to pass the full path when using os.remove function. Also, open function just returns the file object. You need to read the lines from the file. And don't forget to close the file. A solution would be:
import os
path = "c:\\Users\\SFMe\\Desktop\\DeleteFolder"
os.chdir(path)
# added the argument "r" to indicates only reading
list_file = open('DeleteFiles.txt', "r")
# changing variable list to _list to do not shadow
# the built-in function and type list
_list = list_file.read().splitlines()
list_file.close()
for f in _list:
os.remove(os.path.join(path,f))
A further improvement would be use list comprehension instead of a loop and a with block, which "automagically" closes the file for us:
with open('DeleteFiles.txt', "r") as list_file:
_list = list_file.read().splitlines()
[os.remove(os.path.join(path,f)) for f in _list]

Going through all folders in Python

I want to go through all folders inside a directory:
directory\
folderA\
a.cpp
folderB\
b.cpp
folderC\
c.cpp
folderD\
d.cpp
The name of the folders are all known.
Specifically, I am trying to count the number of lines of code on each of the a.cpp, b.cpp, c.pp and d.cpp source files. So, go inside folderA and read a.cpp, count lines and then go back to directory, go inside folderB, read b.cpp, count lines etc.
This is what I have up until now,
dir = directory_path
for folder_name in folder_list():
dir = os.path.join(dir, folder_name)
with open(dir) as file:
source= file.read()
c = source.count_lines()
but I am new to Python and have no idea if my approach is appropriate and how to proceed. Any example code shown will be appreciated!
Also, does the with open handles the file opening/closing as it should for all those reads or more handling is required?
I would do it like this:
import glob
import os
path = 'C:/Users/me/Desktop/' # give the path where all the folders are located
list_of_folders = ['test1', 'test2'] # give the program a list with all the folders you need
names = {} # initialize a dict
for each_folder in list_of_folders: # go through each file from a folder
full_path = os.path.join(path, each_folder) # join the path
os.chdir(full_path) # change directory to the desired path
for each_file in glob.glob('*.cpp'): # self-explanatory
with open(each_file) as f: # opens a file - no need to close it
names[each_file] = sum(1 for line in f if line.strip())
print(names)
Output:
{'file1.cpp': 2, 'file3.cpp': 2, 'file2.cpp': 2}
{'file1.cpp': 2, 'file3.cpp': 2, 'file2.cpp': 2}
Regarding the with question, you don't need to close the file or make any other checks. You should be safe as it is now.
You may, however, check if the full_path exists as somebody (you) could mistakenly delete a folder from your PC (a folder from list_of_folders)
You can do this by os.path.isdir which returns True if the file exists:
os.path.isdir(full_path)
PS: I used Python 3.
Use Python 3's os.walk() to traverse all subdirectories and files of a given path, opening each file and do your logic. You can use a 'for' loop to walk it, simplifying your code greatly.
https://docs.python.org/2/library/os.html#os.walk
As manglano said, os.walk()
you can generate a list of folder.
[src for src,_,_ in os.walk(sourcedir)]
you can generate a list of file path.
[src+'/'+file for src,dir,files in os.walk(sourcedir) for file in files]

Python: rename files based on a Python list

I have a directory that contains a thousand or so txt files. I've read and explored these files with glob (searching for specific strings within the file) and I've appended the filenames of the files of interest to a list in Python, like so:
list_of_chosen_files = ['file2.txt', 'file10.txt', 'file17.txt', ...]
I'll be using this list for other things as well, but now I'm trying to figure out how to use the OS module to cross-reference the filenames in the directory against the list above and, if the filename is in that list, to add "1-" to the beginning of the filename. I've saved "1-" in a variable for reuse as well. Here's what I have so far: -
var = "1-"
import os
for filename in os.listdir("."):
if filename == list_of_chosen_files[:]:
os.rename(filename, var+filename)
print filename
It's running without any errors in anaconda, but nothing's printing and none of the files are getting renamed. I feel like it should be such an easy fix, but I'm concerned about poking around directories with the OS module if I don't really know what I'm doing yet.
Any help would be greatly appreciated! Thanks!
Your issue is this line:
if filename == list_of_chosen_files[:]:
You're comparing a single string (filename) to an entire list (list_of_chosen_files[:] just gives you back the whole list). If you want to check if the filename is in the list, use this:
if filename in list_of_chosen_files:
This will check to see if list_of_chosen_files contains filename.
Error : if filename == list_of_chosen_files[:]:
os.listdir(".")is only giving you back the basename results. Not full path. They don't exist in your current working directory. You would need to join them back with the root:
root = 'full Path of your directory'
for item in os.listdir(root):
fullpath = os.path.join(root, item)
os.rename(fullpath, fullpath.replace('filename', 'var+filename'))

Ignore folders with certain filetypes

I'm trying in vain to rewrite my old Powershell script found here - "$_.extension -eq" not working as intended? - for Python.I have no Python experience or knowledge and my 'script' is a mess but it mostly works. The only thing missing is that I would like to be able to ignore folders which don't contain 'mp3s', or whichever filetype I specify. Here is what I have so far -
import os, os.path, fnmatch
path = raw_input("Path : ")
for filename in os.listdir(path):
if os.path.isdir(filename):
os.chdir(filename)
j = os.path.abspath(os.getcwd())
mp3s = fnmatch.filter(os.listdir(j), '*.mp3')
if mp3s:
target = open("pls.m3u", 'w')
for filename in mp3s:
target.write(filename)
target.write("\n")
os.chdir(path)
All I would like to be able to do (if possible) is that when the script is looping through the folders that it ignores those which do NOT contain 'mp3s', and removes the 'pls.m3u'. I could only get the script to work properly if I created the 'pls.m3u' by default. The problem is that that creates a lot of empty 'pls.m3u' files in folders which contain only '.jpg' files for example. You get the idea.
I'm sure this script is blasphemous to Python users but any help would be greatly appreciated.
If I understand correctly, your core problem is that this script is creating a lot of empty pls.m3u files. That's because you're calling open before you've even checked whether you have anything you want to write.
A simple fix would be to change this:
target = open("pls.m3u", 'w')
j = os.path.abspath(os.getcwd())
for filename in os.listdir(j):
(title, extn) = os.path.splitext(filename)
if extn == ".mp3":
target.write(filename)
target.write("\n")
into this:
target = None
j = os.path.abspath(os.getcwd())
for filename in os.listdir(j):
(title, extn) = os.path.splitext(filename)
if extn == ".mp3":
if not target:
target = open("pls.m3u", 'w')
target.write(filename)
target.write("\n")
if target:
target.write("\n")
target.write("\n")
That is, only open the file the first time we decide we need to write to it.
A more Pythonic approach might be to do something like this:
j = os.path.abspath(os.getcwd())
mp3s = [filename for filename in os.listdir(j)
if os.path.splitext(filename)[1] == ".mp3"]
if mp3s:
target = open("pls.m3u", 'w')
for filename in mp3s:
target.write(filename)
target.write("\n")
target.write("\n")
target.write("\n")
That is, first create a list of the mp3s in memory (using a list comprehension here, though you could use a plain old for loop and append if you're more comfortable with that) and then open the file only if the resulting list is non-empty. (lists are truthy if non-empty)
I think you can do it in a two-level approach. First, copy the toplevel directory to another directory ignoring the directories which do not contain your mp3s files.
import shutil
IGNORE_PATTERNS = ('*mp3s')
shutil.copytree(SOURCE_DIR, TARGET_DIR, ignore=shutil.ignore_patterns(IGNORE_PATTERNS))
And then go ahead with the approach you are doing for files in your example code. Note that shutil.copytree has the ignore_patterns only from python2.5

Categories