如何列出目录中的所有文件?
- 2024-11-18 08:40:00
- admin 原创
- 14
问题描述:
如何在 Python 中列出目录中的所有文件并将它们添加到list
?
解决方案 1:
os.listdir()
返回目录内的所有内容 - 包括文件和目录。
os.path
'sisfile()
可用于仅列出文件:
from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]
或者,为每个访问的目录生成两个列表——一个用于文件,一个用于目录。如果你只想要顶级目录,你可以在第一次生成时中断:os.walk()
from os import walk
f = []
for (dirpath, dirnames, filenames) in walk(mypath):
f.extend(filenames)
break
或者更短:
from os import walk
filenames = next(walk(mypath), (None, None, []))[2] # [] if no file
解决方案 2:
我更喜欢使用glob
模块,因为它可以进行模式匹配和扩展。
import glob
print(glob.glob("/home/adam/*"))
它直观地进行模式匹配
import glob
# All files and directories ending with .txt and that don't begin with a dot:
print(glob.glob("/home/adam/*.txt"))
# All files and directories ending with .txt with depth of 2 folders, ignoring names beginning with a dot:
print(glob.glob("/home/adam/*/*.txt"))
它将返回包含查询的文件和目录的列表:
['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]
请注意,glob
忽略以点开头的文件和目录.
,因为这些被视为隐藏文件和目录,除非模式类似于.*
。
用于glob.escape
转义不属于模式的字符串:
print(glob.glob(glob.escape(directory_name) + "/*.txt"))
解决方案 3:
当前目录中的列表
使用listdir
模块os
,您可以获取当前目录中的文件和文件夹
import os
arr = os.listdir()
查看目录
arr = os.listdir('c:\\files')
你glob
可以指定要列出的文件类型,如下所示
import glob
txtfiles = []
for file in glob.glob("*.txt"):
txtfiles.append(file)
或者
mylist = [f for f in glob.glob("*.txt")]
获取当前目录中文件的完整路径
import os
from os import listdir
from os.path import isfile, join
cwd = os.getcwd()
onlyfiles = [os.path.join(cwd, f) for f in os.listdir(cwd) if
os.path.isfile(os.path.join(cwd, f))]
print(onlyfiles)
['G:\\getfilesname\\getfilesname.py', 'G:\\getfilesname\\example.txt']
获取完整路径名os.path.abspath
您将获得完整路径
import os
files_path = [os.path.abspath(x) for x in os.listdir()]
print(files_path)
['F:\\documentiapplications.txt', 'F:\\documenticollections.txt']
遍历:遍历子目录
os.walk 返回根、目录列表和文件列表,这就是为什么我在 for 循环中的 r、d、f 中解压它们;然后,它在根的子文件夹中查找其他文件和目录,依此类推,直到没有子文件夹。
import os
# Getting the current work directory (cwd)
thisdir = os.getcwd()
# r=root, d=directories, f = files
for r, d, f in os.walk(thisdir):
for file in f:
if file.endswith(".docx"):
print(os.path.join(r, file))
在目录树中向上移动
# Method 1
x = os.listdir('..')
# Method 2
x= os.listdir('/')
使用以下方法获取特定子目录的文件os.listdir()
import os
x = os.listdir("./content")
os.walk('.') - 当前目录
import os
arr = next(os.walk('.'))[2]
print(arr)
>>> ['5bs_Turismo1.pdf', '5bs_Turismo1.pptx', 'esperienza.txt']
next(os.walk('.')) 和 os.path.join('dir', 'file')
import os
arr = []
for d,r,f in next(os.walk("F:\\_python")):
for file in f:
arr.append(os.path.join(r,file))
for f in arr:
print(files)
>>> F:\\_python\\dict_class.py
>>> F:\\_python\\programmi.txt
下一步...步行
[os.path.join(r,file) for r,d,f in next(os.walk("F:\\_python")) for file in f]
>>> ['F:\\_python\\dict_class.py', 'F:\\_python\\programmi.txt']
os.walk
x = [os.path.join(r,file) for r,d,f in os.walk("F:\\_python") for file in f]
print(x)
>>> ['F:\\_python\\dict.py', 'F:\\_python\\progr.txt', 'F:\\_python\\readl.py']
os.listdir() - 仅获取 txt 文件
arr_txt = [x for x in os.listdir() if x.endswith(".txt")]
用于glob
获取文件的完整路径
from path import path
from glob import glob
x = [path(f).abspath() for f in glob("F:\\*.txt")]
用于os.path.isfile
避免列表中的目录
import os.path
listOfFiles = [f for f in os.listdir() if os.path.isfile(f)]
pathlib
从 Python 3.4使用
import pathlib
flist = []
for p in pathlib.Path('.').iterdir():
if p.is_file():
print(p)
flist.append(p)
和list comprehension
:
flist = [p for p in pathlib.Path('.').iterdir() if p.is_file()]
在 pathlib.Path() 中使用 glob 方法
import pathlib
py = pathlib.Path().glob("*.py")
使用 os.walk 获取所有文件:仅检查返回的第三个元素,即文件列表
import os
x = [i[2] for i in os.walk('.')]
y=[]
for t in x:
for f in t:
y.append(f)
仅获取目录中的下一个文件:仅返回根文件夹中的文件
import os
x = next(os.walk('F://python'))[2]
使用 next 获取目录并进入目录,因为 [1] 元素中只有文件夹
import os
next(os.walk('F://python'))[1] # for the current dir use ('.')
>>> ['python3','others']
获取所有subdir
名称walk
for r,d,f in os.walk("F:\\_python"):
for dirs in d:
print(dirs)
os.scandir()
来自 Python 3.5 及更高版本
import os
x = [f.name for f in os.scandir() if f.is_file()]
# Another example with `scandir` (a little variation from docs.python.org)
# This one is more efficient than `os.listdir`.
# In this case, it shows the files only in the current directory
# where the script is executed.
import os
with os.scandir() as i:
for entry in i:
if entry.is_file():
print(entry.name)
解决方案 4:
import os
os.listdir("somedirectory")
将返回“somedirectory”中所有文件和目录的列表。
解决方案 5:
一行解决方案仅获取文件列表(无子目录):
filenames = next(os.walk(path))[2]
或绝对路径名:
paths = [os.path.join(path, fn) for fn in next(os.walk(path))[2]]
解决方案 6:
获取目录及其所有子目录的完整文件路径
import os
def get_filepaths(directory):
"""
This function will generate the file names in a directory
tree by walking the tree either top-down or bottom-up. For each
directory in the tree rooted at directory top (including top itself),
it yields a 3-tuple (dirpath, dirnames, filenames).
"""
file_paths = [] # List which will store all of the full filepaths.
# Walk the tree.
for root, directories, files in os.walk(directory):
for filename in files:
# Join the two strings in order to form the full filepath.
filepath = os.path.join(root, filename)
file_paths.append(filepath) # Add it to the list.
return file_paths # Self-explanatory.
# Run the above function and store its results in a variable.
full_file_paths = get_filepaths("/Users/johnny/Desktop/TEST")
我在上面的函数中提供的路径包含 3 个文件 — 其中两个位于根目录中,另一个位于名为“SUBFOLDER”的子文件夹中。您现在可以执行以下操作:
print full_file_paths
这将打印列表:
+ `['/Users/johnny/Desktop/TEST/file1.txt', '/Users/johnny/Desktop/TEST/file2.txt', '/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat']`
如果您愿意,您可以打开并阅读内容,或者只关注扩展名为“.dat”的文件,如下面的代码所示:
for f in full_file_paths:
if f.endswith(".dat"):
print f
/Users/johnny/Desktop/TEST/SUBFOLDER/file3.dat
解决方案 7:
从 3.4 版开始,有了内置迭代器,其效率比以下版本高得多os.listdir()
:
pathlib
:3.4 版本中的新功能。
>>> import pathlib
>>> [p for p in pathlib.Path('.').iterdir() if p.is_file()]
根据PEP 428,该库的目的pathlib
是提供一个简单的类层次结构来处理文件系统路径和用户对其执行的常见操作。
os.scandir()
:3.5 版本中的新功能。
>>> import os
>>> [entry for entry in os.scandir('.') if entry.is_file()]
请注意,从 3.5 版本开始os.walk()
使用os.scandir()
而不是os.listdir()
,并且根据PEP 471 ,其速度提高了 2-20 倍。
我还建议阅读下面 ShadowRanger 的评论。
解决方案 8:
初步说明
尽管问题文本中文件和目录术语有明显区别,但有些人可能认为目录实际上是特殊文件
语句:“目录下的所有文件”可以有两种解释:
1. **仅限**所有**直系**(或 1 级)后代
2. 整个目录树中的所有后代(包括子目录中的后代)
当提出这个问题时,我想象Python 2是LTS版本,但是代码示例将由Python 3 ( .5 )运行(我会尽可能使它们符合Python 2标准;此外,我将发布的任何属于Python的代码均来自v3.5.4 - 除非另有说明)。
这会产生与问题中的另一个关键字相关的后果:“将它们添加到列表中”:
+ *在Python 2.2*之前的版本中,序列(可迭代)大多由列表(元组、集合等)表示。
+ *在Python 2.2*中,引入了**生成器**的概念([Python.Wiki]: 生成器) - 摘自[Python.Docs]: 简单语句 - 收益语句)。随着时间的推移,对于返回/处理列表的函数,开始出现生成器对应物
+ 在*Python 3*中,生成器是默认行为
+ 不确定返回列表是否仍是强制性的(或者生成器也可以),但将生成器传递给*列表*构造函数,将会从中创建一个列表(并使用它)。下面的示例说明了[Python.Docs] 上的差异:内置函数 - map(function, iterable, *iterables)
>>> import sys >>> >>> sys.version '2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)]' >>> m = map(lambda x: x, [1, 2, 3]) # Just a dummy lambda function >>> m, type(m) ([1, 2, 3], <type 'list'>) >>> len(m) 3
>>> import sys >>> >>> sys.version '3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]' >>> m = map(lambda x: x, [1, 2, 3]) >>> m, type(m) (<map object at 0x000001B4257342B0>, <class 'map'>) >>> len(m) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'map' has no len() >>> lm0 = list(m) # Build a list from the generator >>> lm0, type(lm0) ([1, 2, 3], <class 'list'>) >>> >>> lm1 = list(m) # Build a list from the same generator >>> lm1, type(lm1) # Empty list now - generator already exhausted ([], <class 'list'>)
这些示例将基于具有以下结构的名为root_dir的目录(此示例适用于Win,但我在Nix上也使用相同的树)。请注意,我将重复使用控制台:
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq003207219]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> [prompt]> tree /f "root_dir" Folder PATH listing for volume Work Volume serial number is 00000029 3655:6FED E:WORKDEVSTACKOVERFLOWQ003207219ROOT_DIR ¦ file0 ¦ file1 ¦ +---dir0 ¦ +---dir00 ¦ ¦ ¦ file000 ¦ ¦ ¦ ¦ ¦ +---dir000 ¦ ¦ file0000 ¦ ¦ ¦ +---dir01 ¦ ¦ file010 ¦ ¦ file011 ¦ ¦ ¦ +---dir02 ¦ +---dir020 ¦ +---dir0200 +---dir1 ¦ file10 ¦ file11 ¦ file12 ¦ +---dir2 ¦ ¦ file20 ¦ ¦ ¦ +---dir20 ¦ file200 ¦ +---dir3
解决方案
程序化方法
1. [Python.Docs]: os.listdir(path='.')
返回包含path所指定目录中条目名称的列表。该列表按任意顺序排列,不包括特殊条目
'.'
和'..'
...
>>> import os >>> >>> root_dir = "root_dir" # Path relative to current dir (os.getcwd()) >>> >>> os.listdir(root_dir) # List all the items in root_dir ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1'] >>> >>> [item for item in os.listdir(root_dir) if os.path.isfile(os.path.join(root_dir, item))] # Filter items and only keep files (strip out directories) ['file0', 'file1']
一个更详细的例子(code_os_listdir.py):
#!/usr/bin/env python
import os
import sys
from pprint import pformat as pf
def _get_dir_content(path, include_folders, recursive):
entries = os.listdir(path)
for entry in entries:
entry_with_path = os.path.join(path, entry)
if os.path.isdir(entry_with_path):
if include_folders:
yield entry_with_path
if recursive:
for sub_entry in _get_dir_content(entry_with_path, include_folders, recursive):
yield sub_entry
else:
yield entry_with_path
def get_dir_content(path, include_folders=True, recursive=True, prepend_folder_name=True):
path_len = len(path) + len(os.path.sep)
for item in _get_dir_content(path, include_folders, recursive):
yield item if prepend_folder_name else item[path_len:]
def _get_dir_content_old(path, include_folders, recursive):
entries = os.listdir(path)
ret = list()
for entry in entries:
entry_with_path = os.path.join(path, entry)
if os.path.isdir(entry_with_path):
if include_folders:
ret.append(entry_with_path)
if recursive:
ret.extend(_get_dir_content_old(entry_with_path, include_folders, recursive))
else:
ret.append(entry_with_path)
return ret
def get_dir_content_old(path, include_folders=True, recursive=True, prepend_folder_name=True):
path_len = len(path) + len(os.path.sep)
return [item if prepend_folder_name else item[path_len:] for item in _get_dir_content_old(path, include_folders, recursive)]
def main(*argv):
root_dir = "root_dir"
ret0 = get_dir_content(root_dir, include_folders=True, recursive=True, prepend_folder_name=True)
lret0 = list(ret0)
print("{:} {:d}
{:s}".format(ret0, len(lret0), pf(lret0)))
ret1 = get_dir_content_old(root_dir, include_folders=False, recursive=True, prepend_folder_name=False)
print("
{:d}
{:s}".format(len(ret1), pf(ret1)))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}
".format(" ".join(elem.strip() for elem in sys.version.split("
")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("
Done.
")
sys.exit(rc)
注意:
有两种实现方式:
1. 使用生成器的方法(当然在这里似乎没用,因为我立即将结果转换为列表)
2. 经典方法(函数名以**_old**结尾)
使用递归(进入子目录)
对于每个实现,都有两个函数:
+ 以*下划线*( **_** ) 开头的函数:“private”(不应直接调用)——完成所有工作
+ 公共方法(包装上一个方法):它只是从返回的条目中剥离初始路径(如果需要)。这是一个丑陋的实现,但这是我目前能想到的唯一想法
在性能方面,生成器通常会更快一些(考虑创建和 迭代时间),但我没有在递归函数中测试它们,而且我在函数内部对内部生成器进行迭代 - 不知道这对性能有多友好
调整参数以获得不同的结果
输出:
[prompt]> "e:WorkDevVEnvspy_pc064_03.05.04_test0Scriptspython.exe" ".code_os_listdir.py" Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] 064bit on win32 <generator object get_dir_content at 0x000002C080418F68> 22 ['root_dir\\dir0', 'root_dir\\dir0\\dir00', 'root_dir\\dir0\\dir00\\dir000', 'root_dir\\dir0\\dir00\\dir000\\file0000', 'root_dir\\dir0\\dir00\\file000', 'root_dir\\dir0\\dir01', 'root_dir\\dir0\\dir01\\file010', 'root_dir\\dir0\\dir01\\file011', 'root_dir\\dir0\\dir02', 'root_dir\\dir0\\dir02\\dir020', 'root_dir\\dir0\\dir02\\dir020\\dir0200', 'root_dir\\dir1', 'root_dir\\dir1\\file10', 'root_dir\\dir1\\file11', 'root_dir\\dir1\\file12', 'root_dir\\dir2', 'root_dir\\dir2\\dir20', 'root_dir\\dir2\\dir20\\file200', 'root_dir\\dir2\\file20', 'root_dir\\dir3', 'root_dir\\file0', 'root_dir\\file1'] 11 ['dir0\\dir00\\dir000\\file0000', 'dir0\\dir00\\file000', 'dir0\\dir01\\file010', 'dir0\\dir01\\file011', 'dir1\\file10', 'dir1\\file11', 'dir1\\file12', 'dir2\\dir20\\file200', 'dir2\\file20', 'file0', 'file1'] Done.
2. [Python.Docs]: os.scandir(path='.')
仅在Python 3.5+中,反向移植:[PyPI]: scandir:
返回对应于path所给目录中条目的os.DirEntry对象的迭代器。条目以任意顺序产生,特殊条目和不包括在内。
'.'
`'..'`使用scandir()代替listdir()可以显著提高需要文件类型或文件属性信息的代码的性能,因为如果操作系统在扫描目录时提供这些信息,os.DirEntry对象就会公开这些信息。所有os.DirEntry方法都可以执行系统调用,但is_dir()和is_file()通常只需要对符号链接进行系统调用;os.DirEntry.stat()在 Unix 上始终需要系统调用,但在 Windows 上只需要对符号链接进行系统调用。
>>> import os >>> >>> root_dir = os.path.join(".", "root_dir") # Explicitly prepending current directory >>> root_dir '.\\root_dir' >>> >>> scandir_iterator = os.scandir(root_dir) >>> scandir_iterator <nt.ScandirIterator object at 0x00000268CF4BC140> >>> [item.path for item in scandir_iterator] ['.\\root_dir\\dir0', '.\\root_dir\\dir1', '.\\root_dir\\dir2', '.\\root_dir\\dir3', '.\\root_dir\\file0', '.\\root_dir\\file1'] >>> >>> [item.path for item in scandir_iterator] # Will yield an empty list as it was consumed by previous iteration (automatically performed by the list comprehension) [] >>> >>> scandir_iterator = os.scandir(root_dir) # Reinitialize the generator >>> for item in scandir_iterator : ... if os.path.isfile(item.path): ... print(item.name) ... file0 file1
注意:
类似于os.listdir
但它也更灵活(并提供更多功能),更具Python特色(在某些情况下,速度更快)
3. [Python.Docs]: os.walk(top, topdown=True, onerror=None, followlinks=False)
通过自上而下或自下而上遍历目录树来生成目录树中的文件名。对于以目录顶部为根的树中的每个目录(包括顶部本身),它都会生成一个 3 元组 (
dirpath
,dirnames
,filenames
)。
>>> import os >>> >>> root_dir = os.path.join(os.getcwd(), "root_dir") # Specify the full path >>> root_dir 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir' >>> >>> walk_generator = os.walk(root_dir) >>> root_dir_entry = next(walk_generator) # First entry corresponds to the root dir (passed as an argument) >>> root_dir_entry ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir', ['dir0', 'dir1', 'dir2', 'dir3'], ['file0', 'file1']) >>> >>> root_dir_entry[1] + root_dir_entry[2] # Display dirs and files (direct descendants) in a single list ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1'] >>> >>> [os.path.join(root_dir_entry[0], item) for item in root_dir_entry[1] + root_dir_entry[2]] # Display all the entries in the previous list by their full path ['E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file0', 'E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\file1'] >>> >>> for entry in walk_generator: # Display the rest of the elements (corresponding to every subdir) ... print(entry) ... ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0', ['dir00', 'dir01', 'dir02'], []) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00', ['dir000'], ['file000']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir00\\dir000', [], ['file0000']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir01', [], ['file010', 'file011']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02', ['dir020'], []) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020', ['dir0200'], []) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir0\\dir02\\dir020\\dir0200', [], []) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir1', [], ['file10', 'file11', 'file12']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2', ['dir20'], ['file20']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir2\\dir20', [], ['file200']) ('E:\\Work\\Dev\\StackOverflow\\q003207219\\root_dir\\dir3', [], [])
注意:
在场景中,它使用os.scandir(旧版本( Python )上为os.listdir )
它通过在子文件夹中重复执行繁重的工作
4. [Python.Docs]: glob.glob(pathname, *, root_dir=None, dir_fd=None, recursive=False, include_hidden=False)
或者glob.i glob:
返回与pathname匹配的路径名列表(可能为空),该列表必须是包含路径规范的字符串。pathname可以是绝对路径(如)或相对路径(如),并且可以包含 shell 样式的通配符。结果中包含损坏的符号链接(与 shell 中一样)。...在 3.5 版中更改:支持使用“ ”的递归通配符。
/usr/src/Python-1.5/Makefile
`../../Tools//.gif`
**
>>> import glob, os >>> >>> wildcard_pattern = "*" >>> root_dir = os.path.join("root_dir", wildcard_pattern) # Match every file/dir name >>> root_dir 'root_dir\\*' >>> >>> glob_list = glob.glob(root_dir) >>> glob_list ['root_dir\\dir0', 'root_dir\\dir1', 'root_dir\\dir2', 'root_dir\\dir3', 'root_dir\\file0', 'root_dir\\file1'] >>> >>> [item.replace("root_dir" + os.path.sep, "") for item in glob_list] # Strip the dir name and the path separator from begining ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1'] >>> >>> for entry in glob.iglob(root_dir + "*", recursive=True): ... print(entry) ... root_dir\n> root_dirdir0 root_dirdir0dir00 root_dirdir0dir00dir000 root_dirdir0dir00dir000ile0000 root_dirdir0dir00ile000 root_dirdir0dir01 root_dirdir0dir01ile010 root_dirdir0dir01ile011 root_dirdir0dir02 root_dirdir0dir02dir020 root_dirdir0dir02dir020dir0200 root_dirdir1 root_dirdir1ile10 root_dirdir1ile11 root_dirdir1ile12 root_dirdir2 root_dirdir2dir20 root_dirdir2dir20ile200 root_dirdir2ile20 root_dirdir3 root_dirile0 root_dirile1
注意:
使用os.listdir
对于大型树(尤其是启用了递归的情况下),iglob是首选
允许根据名称进行高级过滤(由于通配符)
5. [Python.Docs]: 类 pathlib.Path(*pathsegments)
Python 3.4 +,反向移植:[PyPI]: pathlib2。
>>> import pathlib >>> >>> root_dir = "root_dir" >>> root_dir_instance = pathlib.Path(root_dir) >>> root_dir_instance WindowsPath('root_dir') >>> root_dir_instance.name 'root_dir' >>> root_dir_instance.is_dir() True >>> >>> [item.name for item in root_dir_instance.glob("*")] # Wildcard searching for all direct descendants ['dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1'] >>> >>> [os.path.join(item.parent.name, item.name) for item in root_dir_instance.glob("*") if not item.is_dir()] # Display paths (including parent) for files only ['root_dir\\file0', 'root_dir\\file1']
注意:
这是实现我们目标的一种方式
这是处理路径的OOP风格
提供许多功能
6. [Python 2.Docs]: dircache.listdir(路径)
仅限Python 2
但是,根据[GitHub]: python/cpython - (2.7) cpython/Lib/dircache.py,它只是一个带有缓存的os.listdir的(薄)包装器
def listdir(path): """List directory contents, using cache.""" try: cached_mtime, list = cache[path] del cache[path] except KeyError: cached_mtime, list = -1, [] mtime = os.stat(path).st_mtime if mtime != cached_mtime: list = os.listdir(path) list.sort() cache[path] = mtime, list return list
7. 原生操作系统 API
POSIX特定:
[Man7]:CLOSEDIR(3)
可通过[Python.Docs]获取:ctypes - Python 的外部函数库:
ctypes是 Python 的一个外部函数库。它提供与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。它可用于将这些库包装在纯 Python 中。
没有直接关系,但在使用CTypes之前请检查[SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案)。
代码_ctypes.py:
#!/usr/bin/env python3
import ctypes as cts
import sys
DT_DIR = 4
DT_REG = 8
class NixDirent64(cts.Structure):
_fields_ = (
("d_ino", cts.c_ulonglong),
("d_off", cts.c_longlong),
("d_reclen", cts.c_ushort),
("d_type", cts.c_ubyte),
("d_name", cts.c_char * 256),
)
NixDirent64Ptr = cts.POINTER(NixDirent64)
libc = this_process = cts.CDLL(None, use_errno=True)
opendir = libc.opendir
opendir.argtypes = (cts.c_char_p,)
opendir.restype = cts.c_void_p
readdir = libc.readdir
readdir.argtypes = (cts.c_void_p,)
readdir.restype = NixDirent64Ptr
closedir = libc.closedir
closedir.argtypes = (cts.c_void_p,)
def get_dir_content(path):
ret = [path, [], []]
pdir = opendir(cts.create_string_buffer(path.encode()))
if not pdir:
print("opendir returned NULL (errno: {:d})".format(cts.get_errno()))
return ret
cts.set_errno(0)
while True:
pdirent = readdir(pdir)
if not pdirent:
break
dirent = pdirent.contents
name = dirent.d_name.decode()
if dirent.d_type & DT_DIR:
if name not in (".", ".."):
ret[1].append(name)
elif dirent.d_type & DT_REG:
ret[2].append(name)
if cts.get_errno():
print("readdir returned NULL (errno: {:d})".format(cts.get_errno()))
closedir(pdir)
return ret
def main(*argv):
root_dir = "root_dir"
entries = get_dir_content(root_dir)
print("Entries:
{:}".format(entries))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}
".format(" ".join(elem.strip() for elem in sys.version.split("
")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("
Done.
")
sys.exit(rc)
注意:
它从LibC加载三个函数(libc.so - 在当前进程中加载)并调用它们(有关更多详细信息,请查看[SO]: 如何检查文件是否存在而没有异常?(@CristiFati 的回答) - 第 4 项的最后注释。)。这将使这种方法非常接近Python / C边缘
NixDirent64是来自[Man7]: dirent.h(0P)的struct dirent64的CTypes表示( DT_常量也是如此),来自我的Ubuntu OS。在其他版本/版本上,结构定义可能不同,如果不同,则应更新CTypes别名,否则将产生未定义的行为
它以os.walk的格式返回数据。我没有费心让它递归,但从现有代码开始,这将是一个相当简单的任务
一切都可以在Win上完成,数据(库、函数、结构、常量……)有所不同
输出:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q003207219]> python3.5 ./code_ctypes.py Python 3.5.10 (default, Jan 15 2022, 19:53:00) [GCC 9.3.0] 064bit on linux Entries: ['root_dir', ['dir0', 'dir1', 'dir2', 'dir3'], ['file0', 'file1']] Done.
8. [TimGolden]: win32file.FindFilesW
获胜具体:
使用 Windows Unicode API 检索匹配文件名的列表。API FindFirstFileW/FindNextFileW/Find 关闭函数的接口。
>>> import os, win32file as wfile, win32con as wcon >>> >>> root_dir = "root_dir" >>> root_dir_wildcard = os.path.join(root_dir, "*") >>> entry_list = wfile.FindFilesW(root_dir_wildcard) >>> len(entry_list) # Don't display the whole content as it's too long 8 >>> [entry[-2] for entry in entry_list] # Only display the entry names ['.', '..', 'dir0', 'dir1', 'dir2', 'dir3', 'file0', 'file1'] >>> >>> [entry[-2] for entry in entry_list if entry[0] & wcon.FILE_ATTRIBUTE_DIRECTORY and entry[-2] not in (".", "..")] # Filter entries and only display dir names (except self and parent) ['dir0', 'dir1', 'dir2', 'dir3'] >>> >>> [os.path.join(root_dir, entry[-2]) for entry in entry_list if entry[0] & (wcon.FILE_ATTRIBUTE_NORMAL | wcon.FILE_ATTRIBUTE_ARCHIVE)] # Only display file "full" names ['root_dir\\file0', 'root_dir\\file1']
注意:
win32file.FindFilesW是[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions的一部分,它是WinAPI的Python包装器
9. 使用一些(其他)第三方软件包来实现这个效果
最有可能的是,将依赖于上述内容之一(或多个)(可能略有定制)。
笔记:
代码旨在可移植(除了针对特定区域的地方 - 已标记)或跨越:
+ *操作系统*(*Nix*、*Win*、)
+ *Python*版本(2、3、)
上述变体使用了多种路径样式(绝对路径、相对路径),以说明所使用的“工具”在这个方向上是灵活的
os.listdir和os.scandir使用opendir / readdir / closedir([MS.Learn]:FindFirstFileW 函数(fileapi.h ) / [MS.Learn]:FindNextFileW 函数(fileapi.h) / [MS.Learn]:FindClose 函数(fileapi.h))(来自[GitHub]:python/cpython - (main) cpython/Modules/posixmodule.c)
win32file.FindFilesW也使用这些(Win特定)函数(通过[GitHub]: mhammond/pywin32 - (main) pywin32/win32/src/win32file.i)
_get_dir_content(来自第1点)可以使用以下任何一种方法来实现(有些需要更多工作,有些则需要更少工作)
+ 可以进行一些高级过滤(而不仅仅是文件*与* *目录):**例如,* include_folders参数可以被另一个参数替换(例如*filter_func*),该参数是一个以路径作为参数的函数:(这不会删除任何内容)并且在 _get_dir_content 内部*类似**:(*如果函数因一个条目而失败,它将被跳过),但代码越复杂,执行所需的时间就越长`filter_func=lambda x: True``if not filter_func(entry_with_path): continue`
注意!由于使用了递归,我必须提到我在我的笔记本电脑(Win 10 pc064)上做了一些测试,与这个问题完全无关,当递归级别达到(990 .. 1000)范围内的某个值(recursionlimit - 1000(默认值))时,我得到了StackOverflow :)。如果目录树超出该限制(我不是FS专家,所以我不知道这是否可能),那可能会有问题。
我还必须提到,我没有尝试增加recursionlimit,但理论上,如果目录深度大于最高可能的recursionlimit(在该机器上),总是有失败的可能性。
检查[SO]:_csv.Error:字段大于字段限制(131072)(@CristiFati 的答案)以获取有关该主题的更多详细信息
代码示例仅用于演示目的。这意味着我没有考虑错误处理(我认为没有任何try / except / else / finally块),因此代码不够健壮(原因是:尽可能保持简单和简短)。对于生产,还应添加错误处理
其他方法:
1.仅将Python用作包装器
一切都使用另一种技术完成
该技术源自Python
我所知道的最著名的风格就是所谓的SysAdmin方法:
+ 使用*Python*(或任何编程语言)执行*Shell*命令(并解析其输出)
+ 有些人认为这是一个巧妙的破解
+ 我认为这更像是一种蹩脚的解决方法(*gainarie*),因为操作*本身*是从*Shell*执行的(在本例中为*Cmd ),因此与**Python*没有任何关系
+ 可以在两侧进行过滤(*grep* / *findstr*)或输出格式化,但我不会坚持这样做。另外,我故意使用了*os.system*而不是[Python.Docs]: subprocess - 子进程管理例程(*run*、*check_output*、...)
[prompt]> "e:WorkDevVEnvspy_pc064_03.05.04_test0Scriptspython.exe" -c "import os;os.system(\"dir /b root_dir\")" dir0 dir1 dir2 dir3 file0 file1
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q003207219]> python3.5 -c "import os;os.system(\"ls root_dir\")" dir0 dir1 dir2 dir3 file0 file1
一般来说,应该避免这种方法,因为如果某些命令输出格式在不同的操作系统版本/版本之间略有不同,则解析代码也应该进行调整 - 更不用说不同语言环境之间的差异了。
解决方案 9:
我非常喜欢adamk 的回答,他建议您使用glob()
同名模块中的。这允许您使用*
s 进行模式匹配。
但正如其他人在评论中指出的那样,glob()
可能会因不一致的斜线方向而陷入困境。为了解决这个问题,我建议您使用模块中的join()
和函数,也许还可以使用模块中的函数。expanduser()
`os.pathgetcwd()
os`
举例来说:
from glob import glob
# Return everything under C:Usersadmin that contains a folder called wlp.
glob('C:Usersadmin*wlp')
``上面的内容很糟糕 - 路径已经被硬编码,并且只会在 Windows 上驱动器名称和硬编码到路径中的 s之间起作用。
from glob import glob
from os.path import join
# Return everything under Users, admin, that contains a folder called wlp.
glob(join('Users', 'admin', '*', 'wlp'))
上面的方法效果更好,但它依赖于文件夹名称Users
,该名称在 Windows 上很常见,在其他操作系统上则不常见。它还依赖于用户具有特定名称admin
。
from glob import glob
from os.path import expanduser, join
# Return everything under the user directory that contains a folder called wlp.
glob(join(expanduser('~'), '*', 'wlp'))
这在所有平台上都能完美运行。
另一个很好的例子是,它可以完美地跨平台运行,并且做了一些不同的事情:
from glob import glob
from os import getcwd
from os.path import join
# Return everything under the current directory that contains a folder called wlp.
glob(join(getcwd(), '*', 'wlp'))
希望这些示例能帮助您了解标准 Python 库模块中一些函数的强大功能。
解决方案 10:
def list_files(path):
# returns a list of names (with extension, without full path) of all files
# in folder path
files = []
for name in os.listdir(path):
if os.path.isfile(os.path.join(path, name)):
files.append(name)
return files
解决方案 11:
如果你正在寻找find的 Python 实现,这是我经常使用的方法:
from findtools.find_files import (find_files, Match)
# Recursively find all *.sh files in **/usr/bin**
sh_files_pattern = Match(filetype='f', name='*.sh')
found_files = find_files(path='/usr/bin', match=sh_files_pattern)
for found_file in found_files:
print found_file
因此我用它制作了一个 PyPI包,并且还有一个GitHub 存储库。我希望有人发现它对于此代码有潜在用处。
解决方案 12:
为了获得更好的结果,您可以将模块listdir()
的方法os
与生成器一起使用(还记得吗,生成器是一个功能强大的迭代器,可以保持其状态)。以下代码在两个版本中都可以正常工作:Python 2 和 Python 3。
以下是代码:
import os
def files(path):
for file in os.listdir(path):
if os.path.isfile(os.path.join(path, file)):
yield file
for file in files("."):
print (file)
该listdir()
方法返回给定目录的条目列表。如果给定条目是文件,则该方法os.path.isfile()
返回。并且操作符退出函数但保留其当前状态,并且仅返回被检测为文件的条目的名称。以上所有内容允许我们循环遍历生成器函数。True
`yield`
解决方案 13:
返回绝对文件路径列表,不会递归到子目录
L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]
解决方案 14:
一位明智的老师曾经告诉我:
当做某事有几种既定的方法时,没有一种方法适合所有情况。
因此,我将为问题的一个子集添加一个解决方案:很多时候,我们只想检查文件是否与起始字符串和结束字符串匹配,而不进入子目录。因此,我们希望有一个返回文件名列表的函数,例如:
filenames = dir_filter('foo/baz', radical='radical', extension='.txt')
如果您想先声明两个函数,可以这样做:
def file_filter(filename, radical='', extension=''):
"Check if a filename matches a radical and extension"
if not filename:
return False
filename = filename.strip()
return(filename.startswith(radical) and filename.endswith(extension))
def dir_filter(dirname='', radical='', extension=''):
"Filter filenames in directory according to radical and extension"
if not dirname:
dirname = '.'
return [filename for filename in os.listdir(dirname)
if file_filter(filename, radical, extension)]
pattern
这个解决方案可以很容易地用正则表达式来概括(如果你不希望你的模式总是坚持文件名的开始或结束,你可能需要添加一个参数)。
解决方案 15:
import os
import os.path
def get_files(target_dir):
item_list = os.listdir(target_dir)
file_list = list()
for item in item_list:
item_dir = os.path.join(target_dir,item)
if os.path.isdir(item_dir):
file_list += get_files(item_dir)
else:
file_list.append(item_dir)
return file_list
这里我采用了递归结构。
解决方案 16:
使用生成器
import os
def get_files(search_path):
for (dirpath, _, filenames) in os.walk(search_path):
for filename in filenames:
yield os.path.join(dirpath, filename)
list_files = get_files('.')
for filename in list_files:
print(filename)
解决方案 17:
对于 Python 3.4+,另一个非常易读的变体是使用 pathlib.Path.glob:
from pathlib import Path
folder = '/foo'
[f for f in Path(folder).glob('*') if f.is_file()]
使其更加具体很简单,例如仅在所有子目录中查找不是符号链接的 Python 源文件:
[f for f in Path(folder).glob('**/*.py') if not f.is_symlink()]
解决方案 18:
对于 Python 2:
pip install rglob
然后做
import rglob
file_list = rglob.rglob("/home/base/dir/", "*")
print file_list
解决方案 19:
这是我为此编写的通用函数。它返回文件路径列表,而不是文件名,因为我发现后者更有用。它有几个可选参数,使其用途广泛。例如,我经常将它与pattern='*.txt'
或 等参数一起使用subfolders=True
。
import os
import fnmatch
def list_paths(folder='.', pattern='*', case_sensitive=False, subfolders=False):
"""Return a list of the file paths matching the pattern in the specified
folder, optionally including files inside subfolders.
"""
match = fnmatch.fnmatchcase if case_sensitive else fnmatch.fnmatch
walked = os.walk(folder) if subfolders else [next(os.walk(folder))]
return [os.path.join(root, f)
for root, dirnames, filenames in walked
for f in filenames if match(f, pattern)]
解决方案 20:
我将提供一个示例单行代码,其中可以提供源路径和文件类型作为输入。代码返回带有 csv 扩展名的文件名列表。如果需要返回所有文件,请使用.。这还将递归扫描子目录。
[y for x in os.walk(sourcePath) for y in glob(os.path.join(x[0], '*.csv'))]
根据需要修改文件扩展名和源路径。
解决方案 21:
dircache “自 2.6 版起已弃用:dircache 模块已在 Python 3.0 中删除。”
import dircache
list = dircache.listdir(pathname)
i = 0
check = len(list[0])
temp = []
count = len(list)
while count != 0:
if len(list[i]) != check:
temp.append(list[i-1])
check = len(list[i])
else:
i = i + 1
count = count - 1
print temp
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件