如何列出目录中的所有文件?

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,...

问题描述:

如何在 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()

pathlib3.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 2LTS版本,但是代码示例将由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_dirdir0dir00dir000ile0000
root_dirdir0dir00ile000
root_dirdir0dir01
root_dirdir0dir01ile010
root_dirdir0dir01ile011
root_dirdir0dir02
root_dirdir0dir02dir020
root_dirdir0dir02dir020dir0200
root_dirdir1
root_dirdir1ile10
root_dirdir1ile11
root_dirdir1ile12
root_dirdir2
root_dirdir2dir20
root_dirdir2dir20ile200
root_dirdir2ile20
root_dirdir3
root_dirile0
root_dirile1

注意

  • 使用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 dirent64CTypes表示( 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的一部分,它是WinAPIPython包装器

9. 使用一些(其他)第三方软件包来实现这个效果

最有可能的是,将依赖于上述内容之一(或多个)(可能略有定制)。

笔记:

  • 代码旨在可移植(除了针对特定区域的地方 - 已标记)或跨越:

+ *操作系统*(*Nix*、*Win*、)
+ *Python*版本(2、3、)
  • 上述变体使用了多种路径样式(绝对路径、相对路径),以说明所使用的“工具”在这个方向上是灵活的

  • os.listdiros.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
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用