Multitasking in Python, Reformat and Move - python-3.x

I have a many folders. I want to make .zip format of files and move them to another directory:
for (dir, dirs, files) in os.walk(directory):
for filename in files:
# make zip files
if filename.endswith(".zip"):
# move created zip files
os.rename(dir + '/' + filename, new + '/' + directory + '/' + filename)
The problem is that, after make the zip file, program couldn't find the created file with zip extension. I want to create a zip format and move it to another folder.

You can use the shutil lib:
import shutil
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
shutil.move(src, dst)
Recursively move a file or directory (src) to another location (dst).
If the destination is an existing directory, then src is moved inside
that directory. If the destination already exists but is not a
directory, it may be overwritten depending on os.rename() semantics.
If the destination is on the current filesystem, then os.rename() is
used. Otherwise, src is copied (using shutil.copy2()) to dst and then
removed.
Also you can use shutil for archive file:
shutil.make_archive(base_name, format[, root_dir[, base_dir[,
verbose[, dry_run[, owner[, group[, logger]]]]]]])
Create an archive
file (such as zip or tar) and return its name.
For more info read shutil documentation

Related

Moving a folder to itself: shutil, check if file's path is the same as the destination path, if so do nothing

I have the following code which works as expected, expect when the source file is the same as the destination file. I have tried os.path. isfile/isdir/exists but I'm hitting a wall.
So essentially this loops through the file_list and moves the file in the list to the destination. However, it can happen that the source and destination are the same, so, if the file's location is the same as the destination, then it is trying to move itself to itself and obviously fails. So in the following I need to add a check, if the file's location (source) is the same as the destination then pass.
def move_files(file_list, destination):
for file in file_list:
source_file = file
shutil.move(source_file, destination)
In this case the destination is a folder path and the source is a folder path + file name, so I need to ignore the source's file name and compare the path with the destination.
I feel I'm over complicating this, but any help is appreciated.
You can make use of abspath and dirname methods of os.path. The first one returns the absolute path of a directory, the second provides the directory name of a path.
def move_files(file_list, destination):
# just in case you don't provide absolute paths
# you can also consider using `expanduser`
destination = os.path.abspath(destination)
for file in file_list:
file_abs_path = os.path.abspath(file)
if os.path.dirname(file_abs_path) != destination:
shutil.move(file_abs_path, destination)
https://docs.python.org/3/library/os.path.html#os.path.abspath
https://docs.python.org/3/library/os.path.html#os.path.dirname
https://docs.python.org/3/library/os.path.html#os.path.expanduser
I think this is what you want
And also, i've found the source_file variable des nothing special here. So i just ignored it.
import os
import shutil
def move_files(file_list, destination):
dir_lst = os.listdir(destination)
for file in file_list:
if file not in dir_lst: # This will only move the files if its not in the destination folder
shutil.move(file, destination)
For a complete code using only os module,
import os
def move_files(file_list, destination):
dir_lst = os.listdir(destination)
for file in file_list:
if file not in dir_lst: # This will only move the files if its not in the destination folder
os.rename(file, destination)

Renaming Files in Subdirectories using file path

Scenario: I am trying to Rename all .txt file named "a.txt" in all subfolders of a directory.
Question: I came up with the following code, but it has and issue: My loops don't work as expected, I was hoping to get the directory loop, to use the last part of the path, and use that string to rename the file. Right now, my code will rename the file with the latest directory name. How can this be fixed?
Code:
import os
import fnmatch
directory = "C:/Users/DGMS/Desktop/Test"
for root, subdirectories, files in os.walk(directory):
for subdirectory in subdirectories:
pathtest = os.path.basename(os.path.normpath(os.path.join(root, subdirectory)))
print(pathtest)
for file in files:
if fnmatch.fnmatch(file, 'a.txt'):
os.rename(os.path.join(root, file),(os.path.join(root, pathtest)))
print(os.path.join(root, file))
Here is a better code for what you want. All "a.txt" now becomes "b.txt"
import os
rootdir = 'C:/Users/sid/Desktop/test'
for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file == "a.txt"
os.rename(os.path.join(subdir, file),os.path.join(subdir, "b.txt"))

shutil.make_archive not zipping to correct destination

As per the code below I am having issues with the zipping a directory using the python 3 shutil.make_archive function. The .testdir will be zipped but it is being zipped in /home/pi, instead of /home/pi/Backups.
zip_loc = '/home/pi/.testdir'
zip_dest = '/home/pi/Backups/'
shutil.make_archive(zip_loc, 'zip', zip_dest)
Could anyone explain what I am doing wrong?
Reading the docs here I came up with:
zip_loc = '/home/pi/.testdir'
zip_dest = '/home/pi/Backups/'
shutil.make_archive(base_dir=zip_loc, root_dir=zip_loc, format='zip', base_name=zip_dest)
From the docs:
base_name is the name of the file to create, including the path, minus any format-specific extension.
root_dir is a directory that will be the root directory of the archive; for example, we typically chdir into root_dir before creating the archive.
base_dir is the directory where we start archiving from; i.e. base_dir will be the common prefix of all files and directories in the archive.
root_dir and base_dir both default to the current directory.
Before to write the archive, move to the good directory :
old_path = os.getcwd()
os.chdir(path)
-> write the archive
After writing the archive move back to old directory :
os.chdir(old_path)

Scons Copying File on Changes?

Well i have some extra text files, with different extensions, and i need them to be copied to the bin. Right now i am using:
files = []
for root, dirs, files in os.walk("extra_src"):
for file in files:
files.append(["extra_src" + os.sep + file, "bin" + os.sep + file])
for element in files:
command = Command(target = element[1], source = element[0], action = Copy("$TARGET", "$SOURCE"))
Requires(program, command)
Is there any other way to get it to register the files and simply specify all the files in a said directory? I can use Command(..., Copy("dir1", "dir2")) but it doesn't detect changes, and doesn't clean out the bin of those files.
Try something along the lines of:
import os # for os.path.join
inst = env.Install('bin', Glob(os.path.join('extra_src','*.*')))
env.Depends(program, inst) # if required
Note, how the Glob() function will even find files that don't exist yet, but get created by another build step.

Replacing files in one folder and all its subdirectories with modified versions in another folder

I have two folders, one called 'modified' and one called 'original'.
'modified' has no subdirectories and contains 4000 wav files each with unique names.
The 4000 files are copies of files from 'original' except this folder has many subdirectories inside which the original wav files are located.
I want to, for all the wav files in 'modified', replace their name-counterpart in 'original' wherever they may be.
For example, if one file is called 'sound1.wav' in modified, then I want to find 'sound1.wav' in some subdirectory of 'original' and replace the original there with the modified version.
I run Windows 8 so command prompt or cygwin would be best to work in.
As requested, I've written the python code that does the above. I use the 'os' and 'shutil' modules to first navigate over directories and second to overwrite files.
'C:/../modified' refers to the directory containing the files we have modified and want to use to overwrite the originals.
'C:/../originals' refers to the directory containing many sub-directories with files with the same names as in 'modified'.
The code works by listing every file in the modified directory, and for each file, we state the path for the file. Then, we look through all the sub-directories of the original directory, and where the modified and original files share the same name, we replace the original with the modified using shutil.copyfile().
Because we are working with Windows, it was necessary to change the direction of the slashes to '/'.
This is performed for every file in the modified directory.
If anyone ever has the same problem I hope this comes in handy!
import os
import shutil
for wav in os.listdir('C:/../modified'):
modified_file = 'C:/../modified/' + wav
for root, dirs, files in os.walk('C:/../original'):
for name in files:
if name == wav:
original_file = root + '/' + name
original_file = replace_file.replace('\\','/')
shutil.copyfile(modified_file, original_file)
print wav + ' overwritten'
print 'Complete'

Resources