我觉得分配文件和文件夹以及执行+=[item]部分有点麻烦。有什么建议吗?我使用的是Python 3.2
from os import *
from os.path import *
def dir_contents(path):
contents = listdir(path)
files = []
folders = []
for i, item in enumerate(contents):
if isfile(contents[i]):
files += [item]
elif isdir(contents[i]):
folders += [item]
return files, folders
os.walk
和os.scandir
是不错的选择,但是,我越来越多地使用pathlib,使用pathlib可以使用.glob()
或.rglob()
(递归glob(方法:
root_directory = Path(".")
for path_object in root_directory.rglob('*'):
if path_object.is_file():
print(f"hi, I'm a file: {path_object}")
elif path_object.is_dir():
print(f"hi, I'm a dir: {path_object}")
看看os.walk
函数,它返回路径及其包含的目录和文件。这将大大缩短您的解决方案。
对于任何正在寻找使用pathlib
(python >= 3.4
(的解决方案的人
from pathlib import Path
def walk(path):
for p in Path(path).iterdir():
if p.is_dir():
yield from walk(p)
continue
yield p.resolve()
# recursively traverse all files from current directory
for p in walk(Path('.')):
print(p)
# the function returns a generator so if you need a list you need to build one
all_files = list(walk(Path('.')))
然而,如上所述,这并不能保留os.walk
给出的自上而下的排序
由于Python >= 3.4
存在生成器方法Path.rglob
。因此,要处理some/starting/path
下的所有路径,只需执行之类的操作
from pathlib import Path
path = Path('some/starting/path')
for subpath in path.rglob('*'):
# do something with subpath
要获取列表中的所有子路径,请执行list(path.rglob('*'))
。要只获取扩展名为sql
的文件,请执行list(path.rglob('*.sql'))
。
如果您想递归地遍历所有文件,包括子文件夹中的所有文件,我相信这是最好的方法。
import os
def get_files(input):
for fd, subfds, fns in os.walk(input):
for fn in fns:
yield os.path.join(fd, fn)
## now this will print all full paths
for fn in get_files(fd):
print(fn)
自Python 3.4以来,出现了新的模块pathlib
。所以要获得所有的目录和文件,可以做:
from pathlib import Path
dirs = [str(item) for item in Path(path).iterdir() if item.is_dir()]
files = [str(item) for item in Path(path).iterdir() if item.is_file()]
如何使用pathlib
模块遍历目录树的另一个解决方案:
from pathlib import Path
for directory in Path('.').glob('**'):
for item in directory.iterdir():
print(item)
模式**
递归地匹配当前目录和所有子目录,然后方法iterdir
迭代每个目录的内容。当您在遍历目录树时需要更多控制时非常有用。
def dir_contents(path):
files,folders = [],[]
for p in listdir(path):
if isfile(p): files.append(p)
else: folders.append(p)
return files, folders
确实使用
items += [item]
由于许多原因。。。
append
方法已被制作成正是用于(在列表末尾添加一个元素(您正在创建一个元素的临时列表,只是为了将其丢弃。虽然使用Python时不应该首先考虑原始速度(否则你使用的是错误的语言(,但毫无理由地浪费速度似乎不是正确的做法。
您使用的Python语言有点不对称。。。对于列表对象,写入
a += b
与写入a = a + b
不同,因为前者在适当的位置修改对象,而第二者则分配新的列表,如果对象a
也可以使用其他方式访问,则这可能具有不同的语义。在您的特定代码中,情况似乎并非如此,但当其他人(或几年后的您自己,也是如此(不得不修改代码时,这可能会成为一个问题。Python甚至有一个方法extend
,它的语法不那么微妙,专门用于处理您希望通过在另一个列表的末尾添加元素来就地修改列表对象的情况。
正如其他人所指出的,您的代码似乎正在尝试做os.walk
已经做的事情。。。
我使用的不是内置的os.walk和os.path.walk,而是从我在其他地方发现的这段代码中派生出来的东西,我最初链接到了这些代码,但已经替换为内联源:
import os
import stat
class DirectoryStatWalker:
# a forward iterator that traverses a directory tree, and
# returns the filename and additional file information
def __init__(self, directory):
self.stack = [directory]
self.files = []
self.index = 0
def __getitem__(self, index):
while 1:
try:
file = self.files[self.index]
self.index = self.index + 1
except IndexError:
# pop next directory from stack
self.directory = self.stack.pop()
self.files = os.listdir(self.directory)
self.index = 0
else:
# got a filename
fullname = os.path.join(self.directory, file)
st = os.stat(fullname)
mode = st[stat.ST_MODE]
if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode):
self.stack.append(fullname)
return fullname, st
if __name__ == '__main__':
for file, st in DirectoryStatWalker("/usr/include"):
print file, st[stat.ST_SIZE]
它递归地遍历目录,非常高效且易于阅读。
尝试使用append
方法。
在谷歌上搜索相同的信息时,我发现了这个问题。
我在这里发布了我在http://www.pythoncentral.io/how-to-traverse-a-directory-tree-in-python-guide-to-os-walk/(而不是仅仅发布URL,以防链接腐烂(。
该页面有一些有用的信息,还指向其他一些相关页面。
# Import the os module, for the os.walk function
import os
# Set the directory you want to start from
rootDir = '.'
for dirName, subdirList, fileList in os.walk(rootDir):
print('Found directory: %s' % dirName)
for fname in fileList:
print('t%s' % fname)
我还没有对此进行广泛的测试,但我相信这将扩展os.walk
生成器,将目录名连接到所有文件路径,并使生成的列表变平;直接列出搜索路径中的具体文件。
import itertools
import os
def find(input_path):
return itertools.chain(
*list(
list(os.path.join(dirname, fname) for fname in files)
for dirname, _, files in os.walk(input_path)
)
)
import pathlib
import time
def prune_empty_dirs(path: pathlib.Path):
for current_path in list(path.rglob("*"))[::-1]:
if current_path.is_dir() and not any(current_path.iterdir()):
current_path.rmdir()
while current_path.exists():
time.sleep(0.1)
我喜欢os.walk()
的结果结构,但总体上更喜欢pathlib
。因此,我的懒惰解决方案只是从os.walk()
返回的每个项目创建一个Path
。
import os
import pathlib
def walk(path='bin'):
for root, dirs, files in os.walk(path):
root = pathlib.Path(root)
dirs = [root / d for d in dirs]
files = [root / f for f in files]
yield root, dirs, files
这是一个使用os.scandir
并返回树结构的版本。使用os.scandir
将返回os.DirEntry
对象,这些对象包含有关内存中路径对象的信息,从而允许在不调用文件系统的情况下查询有关项的信息。
import os
def treedir(path):
files = []
folders = {}
for entry in os.scandir(path):
if entry.is_file():
files.append(entry)
elif entry.is_dir():
folders[entry.name] = treedir(entry)
result = {}
if files:
result['files'] = files
if folders:
result['folders'] = folders
return result