我有一个C ++ / Obj-C背景,我只是发现了Python(已经写了大约一个小时)。 我正在编写一个脚本,以递归方式读取文件夹结构中的文本文件的内容。
我遇到的问题是我编写的代码只适用于一个文件夹。我可以在代码中看到原因(参见#hardcoded path
),我只是不知道如何继续使用Python,因为我的经验只是全新的。
Python代码:
import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
for folder in subFolders:
outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path
folderOut = open( outfileName, 'w' )
print "outfileName is " + outfileName
for file in files:
filePath = rootdir + '/' + file
f = open( filePath, 'r' )
toWrite = f.read()
print "Writing '" + toWrite + "' to" + filePath
folderOut.write( toWrite )
f.close()
folderOut.close()
答案 0 :(得分:290)
确保您了解os.walk
的三个返回值:
for root, subdirs, files in os.walk(rootdir):
具有以下含义:
root
:当前路径“走过”subdirs
:目录类型<{li>的root
中的文件
files
:目录root
(不在subdirs
)中的文件
请使用os.path.join
而不是用斜杠连接!您的问题是filePath = rootdir + '/' + file
- 您必须连接当前“walked”文件夹而不是最顶层的文件夹。所以那必须是filePath = os.path.join(root, file)
。 BTW“文件”是内置的,因此您通常不会将其用作变量名。
另一个问题是你的循环,应该是这样的,例如:
import os
import sys
walk_dir = sys.argv[1]
print('walk_dir = ' + walk_dir)
# If your current working directory may change during script execution, it's recommended to
# immediately convert program arguments to an absolute path. Then the variable root below will
# be an absolute path as well. Example:
# walk_dir = os.path.abspath(walk_dir)
print('walk_dir (absolute) = ' + os.path.abspath(walk_dir))
for root, subdirs, files in os.walk(walk_dir):
print('--\nroot = ' + root)
list_file_path = os.path.join(root, 'my-directory-list.txt')
print('list_file_path = ' + list_file_path)
with open(list_file_path, 'wb') as list_file:
for subdir in subdirs:
print('\t- subdirectory ' + subdir)
for filename in files:
file_path = os.path.join(root, filename)
print('\t- file %s (full path: %s)' % (filename, file_path))
with open(file_path, 'rb') as f:
f_content = f.read()
list_file.write(('The file %s contains:\n' % filename).encode('utf-8'))
list_file.write(f_content)
list_file.write(b'\n')
如果您不知道,文件的with
语句是简写:
with open('filename', 'rb') as f:
dosomething()
# is effectively the same as
f = open('filename', 'rb')
try:
dosomething()
finally:
f.close()
答案 1 :(得分:56)
如果您使用的是Python 3.5或更高版本,则可以在一行中完成此操作。
import glob
for filename in glob.iglob(root_dir + '**/*.txt', recursive=True):
print(filename)
中所述
如果递归是真的,那么模式&#39; **&#39;将匹配任何文件和零个或多个目录和子目录。
如果您想要每个文件,可以使用
import glob
for filename in glob.iglob(root_dir + '**/*', recursive=True):
print(filename)
答案 2 :(得分:33)
同意Dave Webb,os.walk
将为树中的每个目录生成一个项目。事实上,您只需要关心subFolders
。
这样的代码应该有效:
import os
import sys
rootdir = sys.argv[1]
for folder, subs, files in os.walk(rootdir):
with open(os.path.join(folder, 'python-outfile.txt'), 'w') as dest:
for filename in files:
with open(os.path.join(folder, filename), 'r') as src:
dest.write(src.read())
答案 3 :(得分:6)
我发现以下是最简单的
from glob import glob
import os
files = [f for f in glob('rootdir/**', recursive=True) if os.path.isfile(f)]
使用glob('some/path/**', recursive=True)
获取所有文件,但也包含目录名称。添加if os.path.isfile(f)
条件只会将此列表过滤到现有文件中
答案 4 :(得分:4)
import glob
import os
root_dir = <root_dir_here>
for filename in glob.iglob(root_dir + '**/**', recursive=True):
if os.path.isfile(filename):
with open(filename,'r') as file:
print(file.read())
**/**
用于递归获取所有文件,包括directory
。
if os.path.isfile(filename)
用于检查filename
变量是file
还是directory
,如果它是文件,那么我们可以读取该文件。
我在这里打印文件。
答案 5 :(得分:3)
使用os.path.join()
来构建你的路径 - 它更整洁:
import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
for folder in subFolders:
outfileName = os.path.join(root,folder,"py-outfile.txt")
folderOut = open( outfileName, 'w' )
print "outfileName is " + outfileName
for file in files:
filePath = os.path.join(root,file)
toWrite = open( filePath).read()
print "Writing '" + toWrite + "' to" + filePath
folderOut.write( toWrite )
folderOut.close()
答案 6 :(得分:1)
试试这个:
import os
import sys
for root, subdirs, files in os.walk(path):
for file in os.listdir(root):
filePath = os.path.join(root, file)
if os.path.isdir(filePath):
pass
else:
f = open (filePath, 'r')
# Do Stuff
答案 7 :(得分:1)
如果要给定目录下所有路径的平面列表(如外壳中的find .
):
files = [
os.path.join(parent, name)
for (parent, subdirs, files) in os.walk(YOUR_DIRECTORY)
for name in files + subdirs
]
要仅在基本目录下包含文件的完整路径,请省略+ subdirs
。
答案 8 :(得分:0)
我认为问题在于您没有正确处理os.walk
的输出。
首先,改变:
filePath = rootdir + '/' + file
为:
filePath = root + '/' + file
rootdir
是您固定的起始目录; root
是os.walk
返回的目录。
其次,您不需要缩进文件处理循环,因为为每个子目录运行它是没有意义的。您将root
设置为每个子目录。您不需要手动处理子目录,除非您想对目录本身执行某些操作。
答案 9 :(得分:0)
os.walk
会进行递归遍历。对于每个目录,从root开始它产生一个3元组(dirpath,dirnames,filenames)
from os import walk
from os.path import splitext, join
def select_files(root, files):
"""
simple logic here to filter out interesting files
.py files in this example
"""
selected_files = []
for file in files:
#do concatenation here to get full path
full_path = join(root, file)
ext = splitext(file)[1]
if ext == ".py":
selected_files.append(full_path)
return selected_files
def build_recursive_dir_tree(path):
"""
path - where to begin folder scan
"""
selected_files = []
for root, dirs, files in walk(path):
selected_files += select_files(root, files)
return selected_files
答案 10 :(得分:0)
TL; DR::这等效于find -type f
遍历下面所有目录中的所有文件,包括当前目录:
for currentpath, dirs, files in os.walk('.'):
for file in files:
print(os.path.join(currentpath, file))
正如其他答案中已经提到的那样,os.walk()
是答案,但是可以更好地解释它。很简单!让我们来看看这棵树:
docs/
└── doc1.odt
pics/
todo.txt
使用以下代码:
for currentpath, folders, files in os.walk('.'):
print(currentpath)
currentpath
是它正在查看的当前文件夹。这将输出:
.
./docs
./pics
因此它循环了3次,因为有3个文件夹:当前文件夹docs
和pics
。在每个循环中,它用所有文件夹和文件填充变量dirs
和files
。让我们向他们展示:
for currentpath, folders, files in os.walk('.'):
print(currentpath, dirs, files)
这向我们显示:
# currentpath folders files
. ['pics', 'docs'] ['todo.txt']
./pics [] []
./docs [] ['doc1.odt']
因此,在第一行中,我们看到我们位于文件夹.
中,其中包含两个文件夹,分别为pics
和docs
,并且有一个文件,名为{{ 1}}。您无需执行任何操作即可递归到那些文件夹中,因为如您所见,它会自动递归,并且只为您提供任何子文件夹中的文件。以及它的任何子文件夹(尽管示例中没有这些子文件夹。)
如果您只想遍历所有文件,相当于todo.txt
,则可以执行以下操作:
find -type f
这将输出:
for currentpath, dirs, files in os.walk('.'):
for file in files:
print(os.path.join(currentpath, file))
答案 11 :(得分:0)
pathlib
库非常适合处理文件。您可以像这样在Path
对象上进行递归glob。
from pathlib import Path
for elem in Path('/path/to/my/files').rglob('*.*'):
print(elem)
答案 12 :(得分:0)
如果您喜欢(几乎)Oneliner:
from pathlib import Path
lookuppath = '.' #use your path
filelist = [str(item) for item in Path(lookuppath).glob("**/*") if Path(item).is_file()]
在这种情况下,您将获得一个列表,其中所有文件的路径都以递归方式位于lookuppath下。 没有str(),您将获得PosixPath()添加到每个路径。
答案 13 :(得分:-1)
这对我有用:
import glob
root_dir = "C:\\Users\\Scott\\" # Don't forget trailing (last) slashes
for filename in glob.iglob(root_dir + '**/*.jpg', recursive=True):
print(filename)
# do stuff