If a path is file or directory (Python) - python

I am trying to list all the files in the current folder and also files in the folders of the current folder.
This is what I have been upto:
import os
def sendFnF(dirList):
for file in dirList:
if os.path.isdir(file):
print 'Going in dir:',file
dirList1= os.listdir('./'+file)
# print 'files in list', dirList1
sendFnF(dirList1)
print 'backToPrevDirectory:'
else:
print 'file name is',file
filename= raw_input()
dirList= os.listdir('./'+filename)
sendFnF(dirList)
This code does get me into folders of the current directory. But when it comes to sub-folders; it treats them as files.
Any idea what I am doing wrong?
Thanks in advance,
Sarge.

Prepending ./ to a path does essentially nothing. Also, just because you call a function recursively with a directory path doesn't change the current directory, and thus the meaning of . in a file path.
Your basic approach is right, to go down a directory use os.path.join(). It'd be best to restructure your code so you listdir() at the start of sendFnF():
def sendFnF(directory):
for fname in os.listdir(directory):
# Add the current directory to the filename
fpath = os.path.join(directory, fname)
# You need to check the full path, not just the filename
if os.path.isdir(fpath):
sendFnF(fpath)
else:
# ...
# ...
sendFnf(filename)
That said, unless this is an exercise, you can just use os.walk()

Related

How to move a file in python without knowing the path of the file you want to move? (Half way done)

I am searching for a file and its path in python, I get the result printed with the full path and file I am searching for. How do I set the print result as a variable so I can copy and move it to another folder?
import os
def find_files(filename, search_path):
result = []
for root, dir, files in os.walk(search_path):
if filename in files:
result.append(os.path.join(root, filename))
return result
print(find_files("myfile.exe","C:"))
When I run the .py file, it prints the full path of the file myfile.exe which is great, but how do I set it to get the path inside my function and move it to another folder/path?
I do not want to print the path of the file on the terminal, I want to use that path inside my program so I can use it to move it to another folder.
Thank you very much for your help!
If you extract the single item from result, you get path:
import os
def find_files(filename, search_path):
result = []
for root, dir, files in os.walk(search_path):
if filename in files:
result.append(os.path.join(root, filename))
return result[0]
PATH = find_files("test", r"C:\Users\UserName\Desktop")
PATH
Output:
'C:\\Users\\UserName\\Desktop\\test'

Extract full Path and File Name

Attempting to write a function that walks a file system and returns the absolute path and filename for use in another function.
Example "/testdir/folderA/222/filename.ext".
Having tried multiple versions of this I cannot seem to get it to work properly.
filesCheck=[]
def findFiles(filepath):
files=[]
for root, dirs, files in os.walk(filepath):
for file in files:
currentFile = os.path.realpath(file)
print (currentFile)
if os.path.exists(currentFile):
files.append(currentFile)
return files
filesCheck = findFiles(/testdir)
This returns
"filename.ext" (only one).
Substitute in currentFile = os.path.join(root, file) for os.path.realpath(file) and it goes into a loop in the first directory. Tried os.path.join(dir, file) and it fails as one of my folders is named 222.
I have gone round in circles and get somewhat close but haven't been able to get it to work.
Running on Linux with Python 3.6
There's a several things wrong with your code.
There are multiple values are being assigned to the variable name files.
You're not adding the root directory to each filename os.walk() returns which can be done with os.path.join().
You're not passing a string to the findFiles() function.
If you fix those things there's no longer a need to call os.path.exists() because you can be sure it does.
Here's a working version:
import os
def findFiles(filepath):
found = []
for root, dirs, files in os.walk(filepath):
for file in files:
currentFile = os.path.realpath(os.path.join(root, file))
found.append(currentFile)
return found
filesCheck = findFiles('/testdir')
print(filesCheck)
Hi I think this is what you need. Perhaps you could give it a try :)
from os import walk
path = "C:/Users/SK/Desktop/New folder"
files = []
for (directoryPath, directoryNames, allFiles) in walk(path):
for file in allFiles:
files.append([file, f"{directoryPath}/{file}"])
print(files)
Output:
[ ['index.html', 'C:/Users/SK/Desktop/New folder/index.html'], ['test.py', 'C:/Users/SK/Desktop/New folder/test.py'] ]

python: collect files with one extention from all sub-dir

I am trying to collect all files with all sub-directories and move to another directory
Code used
#collects all mp3 files from folders to a new folder
import os
from pathlib import Path
import shutil
#run once
path = os.getcwd()
os.mkdir("empetrishki")
empetrishki = path + "/empetrishki" #destination dir
print(path)
print(empetrishki)
#recursive collection
for root, dirs, files in os.walk(path, topdown=True, onerror=None, followlinks=True):
for name in files:
filePath = Path(name)
if filePath.suffix.lower() == ".mp3":
print(filePath)
os.path.join
filePath.rename(empetrishki.joinpath(filePath))
I have trouble with the last line of moving files: filePath.rename() nor shutil.move nor joinpath() have worked for me. Maybe that's because I am trying to change the element in the tuple - the output from os.walk
Similar code works with os.scandir but this would collect files only in the current directory
How can I fix that, thanks!
If you use pathlib.Path(name) that doesn't mean that something exists called name. Hence, you do need to be careful that you have a full path, or relative path, and you need to make sure to resolve those. In particular I am noting that you don't change your working directory and have a line like this:
filePath = Path(name)
This means that while you may be walking down the directory, your working directory may not be changing. You should make your path from the root and the name, it is also a good idea to resolve so that the full path is known.
filePath = Path(root).joinpath(name).resolve()
You can also place the Path(root) outside the inner loop as well. Now you have an absolute path from '/home/' to the filename. Hence, you should be able to rename with .rename(), like:
filePath.rename(x.parent.joinpath(newname))
#Or to another directory
filePath.rename(other_dir.joinpath(newname))
All together:
from pathlib import os, Path
empetrishki = Path.cwd().joinpath("empetrishki").resolve()
for root, dirs, files in os.walk(path, topdown=True, onerror=None, followlinks=True):
root = Path(root).resolve()
for name in files:
file = root.joinpath(name)
if file.suffix.lower() == ".mp3":
file.rename(empetrishki.joinpath(file.name))
for root, dirs, files in os.walk(path, topdown=True, onerror=None, followlinks=True):
if root == empetrishki:
continue # skip the destination dir
for name in files:
basename, extension = os.path.splitext(name)
if extension.lower() == ".mp3":
oldpath = os.path.join(root, name)
newpath = os.path.join(empetrishki, name)
print(oldpath)
shutil.move(oldpath, newpath)
This is what I suggest. Your code is running on the current directory, and the file is at the path os.path.join(root, name) and you need to provide such path to your move function.
Besides, I would also suggest to use os.path.splitext for extracting the file extension. More pythonic. And also you might want to skip scanning your target directory.

Excluding all but a single subdirectory from a file search

I have a directory structure that resembles the following:
Dir1
Dir2
Dir3
Dir4
L SubDir4.1
L SubDir4.2
L SubDir4.3
I want to generate a list of files (with full paths) that include all the contents of Dirs1-3, but only SubDir4.2 inside Dir4. The code I have so far is
import fnmatch
import os
for root, dirs, files in os.walk( '.' )
if 'Dir4' in dirs:
if not 'SubDir4.2' in 'Dir4':
dirs.remove( 'Dir4' )
for file in files
print os.path.join( root, file )
My problem is that the part where I attempt to exclude any file that does not have SubDir4.2 in it's path is excluding everything in Dir4, including the things I would like to remain. How should I amend that above to to do what I desire?
Update 1: I should add that there are a lot of directories below Dir4 so manually listing them in an excludes list isn't a practical option. I'd like to be able to specify SubDur4.2 as the only subdirectory within Dir4 to be read.
Update 2: For reason outside of my control, I only have access to Python version 2.4.3.
There are a few typos in your snippet. I propose this:
import os
def any_p(iterable):
for element in iterable:
if element:
return True
return False
include_dirs = ['Dir4/SubDir4.2', 'Dir1/SubDir4.2', 'Dir3', 'Dir2'] # List all your included folder names in that
for root, dirs, files in os.walk( '.' ):
dirs[:] = [d for d in dirs if any_p(d in os.path.join(root, q_inc) for q_inc in include_dirs)]
for file in files:
print file
EDIT: According to comments, I have changed that so this is include list, instead of an exclude one.
EDIT2: Added a any_p (any() equivalent function for python version < 2.5)
EDIT3bis: if you have other subfolders with the same name 'SubDir4.2' in other folders, you can use the following to specify the location:
include_dirs = ['Dir4/SubDir4.2', 'Dir1/SubDir4.2']
Assuming you have a Dir1/SubDir4.2.
If they are a lot of those, then you may want to refine this approach with fnmatch, or probably a regex query.
I altered mstud's solution to give you what you are looking for:
import os;
for root, dirs, files in os.walk('.'):
# Split the root into its path parts
tmp = root.split(os.path.sep)
# If the lenth of the path is long enough to be your path AND
# The second to last part of the path is Dir4 AND
# The last part of the path is SubDir4.2 THEN
# Stop processing this pass.
if (len(tmp) > 2) and (tmp[-2] == 'Dir4') and (tmp[-1] != 'SubDir4.2'):
continue
# If we aren't in Dir4, print the file paths.
if tmp[-1] != 'Dir4':
for file in files:
print os.path.join(root, file)
In short, the first "if" skips the printing of any directory contents under Dir4 that aren't SubDir4.2. The second "if" skips the printing of the contents of the Dir4 directory.
for root, dirs, files in os.walk('.'):
tmp = root.split(os.path.sep)
if len(tmp)>2 and tmp[-2]=="Dir4" and tmp[-1]=="SubDir4.2":
continue
for file in files:
print os.path.join(root, file)

Python program to traverse directories and read file information

I'm just getting started with Python but already have found it much more productive than Bash shell scripting.
I'm trying to write a Python script that will traverse every directory that branches from the directory I launch the script in, and for each file it encounters, load an instance of this class:
class FileInfo:
def __init__(self, filename, filepath):
self.filename = filename
self.filepath = filepath
The filepath attribute would be the full absolute path from root (/). Here's the pseudocode mockup for what I'd like the main program to do:
from (current directory):
for each file in this directory,
create an instance of FileInfo and load the file name and path
switch to a nested directory, or if there is none, back out of this directory
I've been reading about os.walk() and ok.path.walk(), but I'd like some advice about what the most straightforward way to implement this in Python would be. Thanks in advance.
I'd use os.walk doing the following:
def getInfos(currentDir):
infos = []
for root, dirs, files in os.walk(currentDir): # Walk directory tree
for f in files:
infos.append(FileInfo(f,root))
return infos
Try
info = []
for path, dirs, files in os.walk("."):
info.extend(FileInfo(filename, path) for filename in files)
or
info = [FileInfo(filename, path)
for path, dirs, files in os.walk(".")
for filename in files]
to get a list of one FileInfo instance per file.
Try it
import os
for item in os.walk(".", "*"):
print(item)

Categories