I want to return the path of a file, If it is found by the program, but I want it to continue to loop(or recursively repeat) the program until all files are checked.
def findAll(fname, path):
for item in os.listdir(path):
n = os.path.join(path, item)
try:
findAll(n, fname)
except:
if item == fname:
print(os.idontknow(item))
So I'm having trouble with calling the path, right now I have
os.idontknow(item)
as a place holder
Input is :
findAll('fileA.txt', 'testpath')
The output is:
['testpat\\fileA.txt', 'testpath\\folder1\\folder11\\fileA.txt','testpath\\folder2\\fileA.txt']
Per my comment above, here is an example that will start at the current directory and search through all sub-directories, looking for files matching fname:
import os
# path is your starting point - everything under it will be searched
path = os.getcwd()
fname = 'file1.txt'
my_files = []
# Start iterating, and anytime we see a file that matches fname,
# add to our list
for root, dirs, files in os.walk(path):
for name in files:
if name == fname:
# root here is the path to the file
my_files.append(os.path.join(root, name))
print my_files
Or as a function (more appropriate for your case :) ):
import os
def findAll(fname, start_dir=os.getcwd()):
my_files = []
for root, dirs, files in os.walk(start_dir):
for name in files:
if name == fname:
my_files.append(os.path.join(root, name))
return my_files
print findAll('file1.txt')
print findAll('file1.txt', '/some/other/starting/directory')
Something like this, maybe?
import os
path = "path/to/your/dir"
for (path, dirs, files) in os.walk(path):
print files
Related
I want to get my script to read a list of names from a list(txt), then search for those in a selected folder with subfolders, then copy and paste those files to another selected folder. My script running without error but no result.
My script:
import os
import os.path
import shutil
textFile = ("D:\\Test\\list.txt")
sourceFolder = ("D:\\Test")
destinationFolder = ("D:\\")
filesToFind = []
with open(textFile, "r") as tx:
for row in tx:
filesToFind.append(row.strip())
for root, dirs, filename in os.walk(sourceFolder):
if filename in filesToFind:
f = os.path.join(root, filename)
shutil.copy(f, destinationFolder)
Haven’t test it but I think this will work - change this:
for root, dirs, filename in os.walk(sourceFolder):
if filename in filesToFind:
f = os.path.join(root, filename)
shutil.copy(f, destinationFolder)
To this:
for root, dirs, filenames in os.walk(sourceFolder):
for filename in filenames:
if filename in filesToFind:
f = os.path.join(root, filename)
shutil.copy(f, destinationFolder)
# Same code using glob #
## More efficient and also tested one ##
## One more feature added- checks file name given present or not ##
import os
import os.path
import shutil
import glob
textFile = ("D:\\Test\\list.txt")
sourceFolder = ("D:\Test")
destinationFolder = ("D:\\")
f = open(textFile, "r").readlines()
for i in f:
ListFile= glob.glob(os.path.join(sourceFolder,"**",i.strip()),recursive=True)
if len(ListFile):
print(ListFile[0],destinationFolder,os.path.basename(ListFile[0]))
destinationfile=os.path.join(destinationFolder,os.path.basename(ListFile[0]))
shutil.copyfile(ListFile[0],destinationfile)
else:
print(i,"-File not found")
I had files that were in zips. I unzipped them with Zip-7 so they are in folders with the zip file names.
Each of these folders has either a .otf or .ttf (some have both) that I want out of them and moved to another folder.
I have tried a few methods of getting the full path of the files but every one of them leaves out the folder that the file is actually in.
Here is my latest try:
import os
import shutil
from pathlib import Path
result = []
for root, dirs, files in os.walk("."):
for d in dirs:
continue
for f in files:
if f.endswith(".otf"):
print(f)
p = Path(f).absolute()
parent_dir = p.parents[1]
p.rename(parent_dir / p.name)
elif f.endswith(".ttf"):
print(f)
p = Path(f).absolute()
parent_dir = p.parents[1]
p.rename(parent_dir / p.name)
else:
continue
Other attempts:
# parent_dir = Path(f).parents[1]
# shutil.move(f, parent_dir)
#print("OTF: " + f)
# fn = f
# f = f[:-4]
# f += '\\'
# f += fn
# result.append(os.path.realpath(f))
#os.path.relpath(os.path.join(root, f), "."))
I know this is something simple but I just can't figure it out. Thanks!
You should join the file name with the path name root:
for root, dirs, files in os.walk("."):
for d in dirs:
continue
for f in files:
if f.endswith(".otf"):
p = Path(os.path.join(root, f)).absolute()
parent_dir = p.parents[1]
p.rename(parent_dir / p.name)
elif f.endswith(".ttf"):
p = Path(os.path.join(root, f)).absolute()
parent_dir = p.parents[1]
p.rename(parent_dir / p.name)
else:
continue
for root, dirs, files in os.walk(".")
for d in dirs:
continue
for f in files:
print(os.path.abspath(f))
You can use os.path.abspath() to get a path of a full file
You would also need to still filter for the certain file types.
Lets say the directories hierarchy looks like this:
A(root)
|
B---------C--------D
| | |
fileB.h fileC.png fileD.py
fileC1.jpg
E
|
fileE.py
How can I access all the doc? Or just get the path. Is there a way to iterlate all?
What I do:
path = sys.path[0]
for filename_dir in os.listdir(path):
filename, ext = os.path.splitext(filename_dir)
if ext == '.h':
#do something
elif ext == '.png'
#do something
.....
But as I know listdir can only access the directory where my program's py file located.
This gives only the dirs and files under a directory, but not recursively:
import os
for filename in os.listdir(path):
print filename
If you want to list absolute paths:
import os
def listdir_fullpath(d):
return [os.path.join(d, f) for f in os.listdir(d)]
If you want resursive search, this gives you an iterator that returns 3-tuples including the parent directory, list of directories, and list of files at each iteration:
for i,j,k in os.walk('.'):
print i, j, k
For example:
import os
path = sys.path[0]
for dirname, dirnames, filenames in os.walk(path):
for subdirname in dirnames:
print "FOUND DIRECTORY: ", os.path.join(dirname, subdirname)
for filename in filenames:
print "FOUND FILE: ", os.path.join(dirname, filename)
I want to move files from a complex directory structure to just one place. For example i have this deep hierarchy:
foo/
foo2/
1.jpg
2.jpg
...
I want it to be:
1.jpg
2.jpg
...
My current solution:
def move(destination):
for_removal = os.path.join(destination, '\\')
is_in_parent = lambda x: x.find(for_removal) > -1
with directory(destination):
files_to_move = filter(is_in_parent,
glob_recursive(path='.'))
for file in files_to_move:
shutil.move(file, destination)
Definitions: directory and glob_recursive. Note, that my code only moves files to their common parent directory, not an arbitrary destination.
How can i move all files from a complex hierarchy to a single place succinctly and elegantly?
I don't like testing the name of the file about to be moved to see if we're already in the destination directory. Instead, this solution only scans the subdirectories of the destination
import os
import itertools
import shutil
def move(destination):
all_files = []
for root, _dirs, files in itertools.islice(os.walk(destination), 1, None):
for filename in files:
all_files.append(os.path.join(root, filename))
for filename in all_files:
shutil.move(filename, destination)
Explanation: os.walk walks recursively the destination in a "top down" manner. whole filenames are constructed with the os.path.join(root, filename) call. Now, to prevent scanning files at the top of the destination, we just need to ignore the first element of the iteration of os.walk. To do that I use islice(iterator, 1, None). One other more explicit way would be to do this:
def move(destination):
all_files = []
first_loop_pass = True
for root, _dirs, files in os.walk(destination):
if first_loop_pass:
first_loop_pass = False
continue
for filename in files:
all_files.append(os.path.join(root, filename))
for filename in all_files:
shutil.move(filename, destination)
this would do, it also renames files if they collide (I commented out the actual move and replaced with a copy):
import os
import sys
import string
import shutil
#Generate the file paths to traverse, or a single path if a file name was given
def getfiles(path):
if os.path.isdir(path):
for root, dirs, files in os.walk(path):
for name in files:
yield os.path.join(root, name)
else:
yield path
destination = "./newdir/"
fromdir = "./test/"
for f in getfiles(fromdir):
filename = string.split(f, '/')[-1]
if os.path.isfile(destination+filename):
filename = f.replace(fromdir,"",1).replace("/","_")
#os.rename(f, destination+filename)
shutil.copy(f, destination+filename)
Run recursively through directory, move the files and launch move for directories:
import shutil
import os
def move(destination, depth=None):
if not depth:
depth = []
for file_or_dir in os.listdir(os.path.join([destination] + depth, os.sep)):
if os.path.isfile(file_or_dir):
shutil.move(file_or_dir, destination)
else:
move(destination, os.path.join(depth + [file_or_dir], os.sep))
import os.path, shutil
def move(src, dest):
not_in_dest = lambda x: os.path.samefile(x, dest)
files_to_move = filter(not_in_dest,
glob_recursive(path=src))
for f in files_to_move:
shutil.move(f, dest)
Source for glob_recursive. Does not change name of file, if they collide.
samefile is a safe way to compare paths. But it doesn't work on Windows, so check How to emulate os.path.samefile behaviour on Windows and Python 2.7?.
def splitPath(p):
a,b = os.path.split(p)
return (splitPath(a) if len(a) and len(b) else []) + [b]
def safeprint(s):
try:
print(s)
except UnicodeEncodeError:
if sys.version_info >= (3,):
print(s.encode('utf8').decode(sys.stdout.encoding))
else:
print(s.encode('utf8'))
def flatten(root, doit):
SEP = "¦"
REPL = "?"
folderCount = 0
fileCount = 0
if not doit:
print("Simulating:")
for path, dirs, files in os.walk(root, topdown=False):
if path != root:
for f in files:
sp = splitPath(path)
np = ""
for element in sp[1:]:
e2 = element.replace(SEP, REPL)
np += e2 + SEP
f2 = f.replace(SEP, REPL)
newName = np + f2
safeprint("Moved: "+ newName )
if doit:
shutil.move(os.path.join(path, f), os.path.join(root, f))
# Uncomment, if you want filenames to be based on folder hierarchy.
#shutil.move(os.path.join(path, f), os.path.join(root, newName))
fileCount += 1
safeprint("Removed: "+ path)
if doit:
os.rmdir(path)
folderCount += 1
if doit:
print("Done.")
else:
print("Simulation complete.")
print("Moved files:", fileCount)
print("Removed folders:", folderCount)
directory_path = r"C:\Users\jd\Documents\myFtpData"
flatten(directory_path, True)
Adding on to the answers, I believe my answer will satisfy all your needs, the other answers fail when there is a subdirectory and file with the same filename as the upper directory.
This was SOLVED here, Also look at my Github Repo for Structured File Copy and Flattened File Copy:
import os, fnmatch, shutil
PATTERN = '*.txt' # Regex Pattern to Match files
INPUT_FOLDER = "A" # os.getcwd()
INPUT_FOLDER = os.path.abspath(INPUT_FOLDER)
include_input_foldername = False
prepend = "_included" if include_input_foldername else ""
OUTPUT_FOLDER = f"Structured_Copy_{os.path.basename(INPUT_FOLDER)}{prepend}"
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
def find(pattern, path):
"""Utility to find files wrt a regex search"""
result = []
for root, dirs, files in os.walk(path):
for name in files:
if fnmatch.fnmatch(name, pattern):
result.append(os.path.join(root, name))
return result
all_files = find(PATTERN, INPUT_FOLDER)
for each_path in all_files:
relative_path = os.path.relpath(each_path, os.path.dirname(INPUT_FOLDER)) if include_input_foldername else os.path.relpath(each_path, INPUT_FOLDER)
flattened_relative_fullpath = os.path.join(OUTPUT_FOLDER, relative_path)
os.makedirs(os.path.dirname(flattened_relative_fullpath), exist_ok=True)
shutil.copy(each_path, flattened_relative_fullpath)
print(f"Copied {each_path} to {flattened_relative_fullpath}")
print(f"Finished Copying {len(all_files)} Files from : {INPUT_FOLDER} to : {OUTPUT_FOLDER}")
Functions return the position of master well in python.
def myPath():
for root,dirs,files in os.walk(dir):
for fn in files:
path = os.path.join(root, fn)
return path
return path
return path
ls /home/bb/C/
a.out main.c simple_write t.c
Three positions "return" is not what I want.
I want to get result "All the files in the C"
def filesize(path):
for root, dirs, files in os.walk(PATH):
for fn in files:
path = os.path.join(root, fn)
size = os.stat(path).st_size
yield size,path
for size,path in filesize(PATH):
print size,path
but,How to achieve the above functions with the following code? How to modify it?
def find(path):
return [os.path.join(root,fn)
for root,dir,files in os.walk(dirs)
for fn in files]
Return a list of the paths, not only a single path:
def find(path):
return [os.path.join(root, fn)
for root, dirs, files in os.walk(path)
for fn in files]
You could also use yield inside the inner loop to get a generator function, see The Python yield keyword explained.
What you want is a generator:
def myPath(mydir):
for root,dirs,files in os.walk(mydir):
for fn in files:
path = os.path.join(root, fn)
yield path # <----- Instead of return
for path in myPath(some_dir):
print path
Here are 3 ways if you need just the /home/bb/C directory listed
import os, glob
def listWithoutDirectories(path):
return [os.path.join(root,fn)
for root,dirs,files in os.walk(mydir)
if(root==path)
for fn in files]
def listWithDirectories(path)
return [os.path.join(path,fn)
for fn in os.listdir(path)]
print listWithoutDirectories('/home/bb/C')
print listWithDirectories('/home/bb/C')
#Or with a glob
print glob.glob('/home/bb/C/*')