Very new to Python so please bear with me. I would like to move only the contents of a directory if it exist. Otherwise, would like to move the entire directory. Cleaning up the input directory would be ideal too. Here is what I have so far, for some reason this isn't working:
#!/usr/bin/python
import sys, os, glob, shutil
in_dir = '/images_in/'
out_dir = '/images_out/'
new_dirs = os.listdir(in_dir)
old_dirs = os.listdir(out_dir)
#See if directory already exists. If it doesnt exists, move entire
directory. If it does exists, move only new images.
for dir in new_dirs:
if dir not in old_dirs:
shutil.move(dir, out_dir)
else:
new_images = glob.glob(in_dir + dir + '*.jpg')
for i in new_images:
shutil.move(i, out_dir + dir + i)
The problem is that when you do:
for i in new_images:
shutil.move(i, out_dir + dir + i)
the target path is incorrect. See i is the result of glob.glob on an absolute path. So prepending another absolute path is wrong. You have to use the base name of i instead.
I would do:
for i in new_images:
shutil.move(i, os.path.join(out_dir, dir, os.path.basename(i)))
Aside:
put old_dirs in a set so lookup with in is faster: old_dirs = set(os.listdir(out_dir))
use os.path.join instead of string concatenation when handling path parts (as I did in my solution). Ex: new_images = glob.glob(os.path.join(in_dir,dir,'*.jpg')
dir is a built-in to list a module contents, that you're shadowing. Not a big concern, but better to avoid it.
Related
I'm working with python and I need to rename the files that I have inside a directory for example:
C:\Users\lenovo\Desktop\files\file1.txt
C:\Users\lenovo\Desktop\file\file2.txt
C:\Users\lenovo\Desktop\files\file3.txt
I have these 3 files inside the files folder, and I want to change the name of these, I have my script inside another folder: C:\Users\lenovo\Desktop\app\rename.py
I don't know if this is the problem but this is what I tried and it didn't work for me:
import os
directory = r'C:\Users\lenovo\Desktop\files'
count=0
for filename in os.listdir(directory):
count +=1
f = os.path.join(directory, filename)
if os.path.isfile(f):
os.rename(f, "new_file"+str(count))
UPDATE
the code simply deletes the original files and tries to create others inside the folder where I have the python script.
You need to prepend the directory to the new files
import os
directory = r'C:\Users\lenovo\Desktop\files'
count=0
for filename in os.listdir(directory):
count +=1
f = os.path.join(directory, filename)
new_f = os.path.join(directory, "new_file"+str(count)+".txt")
if os.path.isfile(f):
os.rename(f, new_f)
In general, when in doubt, it's best to use long/absolute path names when renaming/moving files. If you want to rename a file in its current directory, use the full path name in the target file name, as well. So, try changing the line:
os.rename(f, "new_file"+str(count))
to:
os.rename(f, os.path.join(directory, "new_file"+str(count)))
This absolute path will rename each file in its original directory. Otherwise, as you've experienced, relative file names are treated as relative to the directory of the executable.
Once you do the above, you'll probably want to do more tweaks to get a better result, but this should get you closer to your objective.
You used a relative path for the target filename, so the operating system based the path on the current working directory. That CWD was also your script path hints that you ran the program from your script path.
You could use os.path.join to make the path relative to your target directory. But you could also use pathlib
from pathlib import Path
directory = Path(r'C:\Users\lenovo\Desktop\files')
count = 0
for target in Path.iterdir():
if target.is_file():
target.replace(directory/f"newfile{count}")
count += 1
I am fairly new to python, and trying to write a program that organizes files based on their extensions
import os
import shutil
newpath1 = r'C:\Users\User1\Documents\Downloads\Images'
if not os.path.exists(newpath1): # check to see if they already exist
os.makedirs(newpath1)
newpath2 = r'C:\Users\User1\Documents\Downloads\Documents'
if not os.path.exists(newpath2):
os.makedirs(newpath2)
newpath3 = r'C:\Users\User1\Documents\Downloads\Else'
if not os.path.exists(newpath3):
os.makedirs(newpath3)
source_folder = r"C:\Users\User1\Documents\Downloads" # the location of the files we want to move
files = os.listdir(source_folder)
for file in files:
if file.endswith(('.JPG', '.png', '.jpg')):
shutil.move(os.path.join(source_folder,file), os.path.join(newpath1,file))
elif file.endswith(('.pdf', '.pptx')):
shutil.move(os.path.join(source_folder,file), os.path.join(newpath2,file))
#elif file is folder:
#do nothing
else:
shutil.move(os.path.join(source_folder,file), os.path.join(newpath3,file))
I want it to move files based on their extensions. However, I am trying to figure out how to stop the folders from moving. Any help would be greatly appreciated.
Also, for some reason, not every file is being moved, even though they have the same extension.
As with most path operations, I recommend using the pathlib module. Pathlib is available since Python 3.4 and has portable (multi platform), high-level API for file system operations.
I recommend using the following methods on Path objects, to determine their type:
Path.is_file()
Path.is_dir()
import shutil
from pathlib import Path
# Using class for nicer grouping of target directories
# Note that pathlib.Path enables Unix-like path construction, even on Windows
class TargetPaths:
IMAGES = Path.home().joinpath("Documents/Downloads/Images")
DOCUMENTS = Path.home().joinpath("Documents/Downloads/Documents")
OTHER = Path.home().joinpath("Documents/Downloads/Else")
__ALL__ = (IMAGES, DOCUMENTS, OTHER)
for target_dir in TargetPaths.__ALL__:
if not target_dir.is_dir():
target_dir.mkdir(exist_ok=True)
source_folder = Path.home().joinpath("Documents/Downloads") # the location of the files we want to move
# Get absolute paths to the files in source_folder
# files is a generator (only usable once)
files = (path.absolute() for path in source_folder.iterdir() if path.is_file())
def move(source_path, target_dir):
shutil.move(str(source_path), str(target_dir.joinpath(file.name))
for path in files:
if path.suffix in ('.JPG', '.png', '.jpg'):
move(path, TargetPaths.IMAGES)
elif path.suffix in ('.pdf', '.pptx'):
move(path, TargetPaths.DOCUMENTS)
else:
move(path, TargetPaths.OTHER)
See here
In particular, the os.walk command. This command returns a 3-tuple with the dirpath, dirname, and filename.
In your case, you should use [x[0] for x in os.walk(dirname)]
I know how to use python to check to see if a file exists, but what I am after is trying to see if multiple files of the same name exist throughout my working directory. Take for instance:
gamedata/areas/
# i have 2 folders in this directory
# testarea and homeplace
1. gamedata/areas/testarea/
2. gamedata/areas/homeplace/
Each folder of homeplace and testarea for instance contains a file called 'example'
Is there a pythonic way to use 'os' or similiar to check to see if the file 'example' can be found in both testarea and homeplace?
Although is their a way to do this without manually and statically using
os.path.isfile()
because throughout the life of the program new directories will be made, and I don't want to constantly go back into the code to change it.
You can check in every directory bellow gamedata/areas/:
This only goes down one level, you could extend it to go down as many levels as you want.
from os import listdir
from os.path import isdir, isfile, join
base_path = "gamedata/areas/"
files = listdir(base_path)
only_directories = [path for path in files if isdir(join(base_path,path))]
for directory_path in only_directories:
dir_path = join(base_path, directory_path)
for file_path in listdir(dir_path):
full_file_path = join(base_path, dir_path, file_path)
is_file = isfile(full_file_path)
is_example = "example" in file_path
if is_file and is_example:
print "Found One!!"
Hope it helps!
Maybe something like
places = ["testarea", "homeplace"]
if all(os.path.isfile(os.path.join("gamedata/areas/", x, "example") for x in places)):
print("Missing example")
If the condition is false, this doesn't tell you which subdirectory does not contain the file example, though. You can update places as necessary.
As I mentioned in the comments, os.walk is your friend:
import os
ROOT="gamedata/areas"
in_dirs = [path for (path, dirs, filenames)
in os.walk(ROOT)
if 'example' in filenames]
in_dirs will be a list of subdirectories where example is found
This is part of a program I'm writing. The goal is to extract all the GPX files, say at G:\ (specified with -e G:\ at the command line). It would create an 'Exports' folder and dump all files with matching extensions there, recursively that is. Works great, a friend helped me write it!! Problem: empty directories and subdirectories for dirs that did not contain GPX files.
import argparse, shutil, os
def ignore_list(path, files): # This ignore list is specified in the function below.
ret = []
for fname in files:
fullFileName = os.path.normpath(path) + os.sep + fname
if not os.path.isdir(fullFileName) \
and not fname.endswith('gpx'):
ret.append(fname)
elif os.path.isdir(fullFileName) \ # This isn't doing what it's supposed to.
and len(os.listdir(fullFileName)) == 0:
ret.append(fname)
return ret
def gpxextract(src,dest):
shutil.copytree(src,dest,ignore=ignore_list)
Later in the program we have the call for extractpath():
if args.extractpath:
path = args.extractpath
gpxextract(extractpath, 'Exports')
So the above extraction does work. But the len function call above is designed to prevent the creation of empty dirs and does not. I know the best way is to os.rmdir somehow after the export, and while there's no error, the folders remain.
So how can I successfully prune this Exports folder so that only dirs with GPXs will be in there? :)
If I understand you correctly, you want to delete empty folders? If that is the case, you can do a bottom up delete folder operation -- which will fail for any any folders that are not empty. Something like:
for root, dirs, files in os.walk('G:/', topdown=true):
for dn in dirs:
pth = os.path.join(root, dn)
try:
os.rmdir(pth)
except OSError:
pass
I am running a script that walks a directory structure and generates new files in each folder in the directory. I want to delete some of the files right after creation. This is my idea, but it is quite wrong I imagine:
directory = os.path.dirname(obj)
m = MeshExporterApplication(directory)
os.remove(os.path.join(directory,"*.mesh.xml"))
How to you put wildcards in a path? I guess not like /home/me/*.txt, but that is what I am trying.
Thanks,
Gareth
You can use the glob module:
import glob
glob.glob("*.mesh.xml")
to get a list of matching files. Then you delete them, one by one.
directory = os.path.dirname(obj)
m = MeshExporterApplication(directory)
# you can use absolute pathes in the glob
# to ensure, that you're purging the files in
# the right directory, e.g. "/tmp/*.mesh.xml"
for f in glob.glob("*.mesh.xml"):
os.remove(f)
do a for loop with the list of files as the thing you are looping over.
directory = os.path.dirname(obj)
m = MeshExporterApplication(directory)
for filename in os.listdir(dir):
if not(re.match(".*\.mesh\".xml ,filename) is None):
os.remove(directory + "/" + file)