首页 文章

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

提问于
浏览
3105

如何在Python中列出目录的所有文件并将它们添加到 list

22 回答

  • 34

    Returning a list of absolute filepaths, does not recurse into subdirectories

    L = [os.path.join(os.getcwd(),f) for f in os.listdir('.') if os.path.isfile(os.path.join(os.getcwd(),f))]
    
  • 569

    我更喜欢使用glob模块,因为它模式匹配和扩展 .

    import glob
    print(glob.glob("/home/adam/*.txt"))
    

    它将返回包含查询文件的列表:

    ['/home/adam/file1.txt', '/home/adam/file2.txt', .... ]
    
  • 46
    import os
    os.listdir("somedirectory")
    

    将返回“somedirectory”中所有文件和目录的列表 .

  • 8

    获得 only list of files (无子目录)的单行解决方案:

    filenames = next(os.walk(path))[2]
    

    或绝对路径名:

    paths = [os.path.join(path,fn) for fn in next(os.walk(path))[2]]
    
  • 12

    os.listdir()将获取目录中的所有内容 - 文件和目录 .

    如果您只想要文件,可以使用os.path对其进行过滤:

    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
    

    最后,如该示例所示,将一个列表添加到另一个列表,您可以使用.extend()

    >>> q = [1, 2, 3]
    >>> w = [4, 5, 6]
    >>> q = q + w
    >>> q
    [1, 2, 3, 4, 5, 6]
    

    就个人而言,我更喜欢 .extend()

  • 6

    如果您正在寻找 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 package,还有一个GitHub repository . 我希望有人发现它可能对此代码有用 .

  • 4
    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
    

    在这里,我使用递归结构 .

  • 146

    从版本3.4开始,有内置的迭代器,它比os.listdir()更有效:

    pathlib:版本3.4中的新功能 .

    >>> import pathlib
    >>> [p for p in pathlib.Path('.').iterdir() if p.is_file()]
    

    根据PEP 428pathlib库的目的是提供一个简单的类层次结构来处理文件系统路径以及用户对它们执行的常见操作 .

    os.scandir():3.5版中的新功能 .

    >>> import os
    >>> [entry for entry in os.scandir('.') if entry.is_file()]
    

    请注意,os.walk()使用os.scandir()而不是版本3.5中的os.listdir(),根据PEP 471,其速度提高了2-20倍 .

    我还建议您阅读下面的ShadowRanger评论 .

  • 114

    使用发电机

    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)
    
  • 0

    我真的很喜欢adamk's answer,建议您使用同名模块中的 glob() . 这允许您与 * 进行模式匹配 .

    但正如其他人在评论中指出的那样, glob() 可能因不一致的斜线方向而被绊倒 . 为了解决这个问题,我建议您使用 os.path 模块中的 join()expanduser() 函数,也可以使用 os 模块中的 getcwd() 函数 .

    例如:

    from glob import glob
    
    # Return everything under C:\Users\admin that contains a folder called wlp.
    glob('C:\Users\admin\*\wlp')
    

    上面的内容非常糟糕 - 路径已被硬编码,并且只能在Windows上将驱动器名称和 \ 硬编码到路径中 .

    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库模块中可以找到的一些函数的强大功能 .

  • 30
    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
    
  • 1

    如果要使用其他文件类型或获取完整目录,请使用此功能:

    import os
    
    def createList(foldername, fulldir = True, suffix=".jpg"):
        file_list_tmp = os.listdir(foldername)
        #print len(file_list_tmp)
        file_list = []
        if fulldir:
            for item in file_list_tmp:
                if item.endswith(suffix):
                    file_list.append(os.path.join(foldername, item))
        else:
            for item in file_list_tmp:
                if item.endswith(suffix):
                    file_list.append(item)
        return file_list
    
  • 3078

    对于python2:pip install rglob

    import rglob
    file_list=rglob.rglob("/home/base/dir/", "*")
    print file_list
    
  • 1241

    使用Python 2和3获取文件列表


    我还在这里制作了一段短片:Python: how to get a list of file in a directory


    os.listdir()

    或.....如何获取当前目录中的所有文件(和目录)(Python 3)

    在Python 3中将文件放在当前目录中的最简单方法是这样 . 这很简单;使用 os 模块和listdir()函数,你将拥有该目录中的文件(以及目录中的最终文件夹,但你不会在子目录中有文件,因为你可以使用walk - 我会稍后谈谈) .

    >>> import os
    >>> arr = os.listdir()
    >>> arr
    ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']
    

    Using glob

    我发现glob更容易选择相同类型的文件或共同的东西 . 请看以下示例:

    import glob
    
    txtfiles = []
    for file in glob.glob("*.txt"):
        txtfiles.append(file)
    

    使用列表理解

    import glob
    
    mylist = [f for f in glob.glob("*.txt")]
    

    使用os.path.abspath获取完整路径名

    如您所知,您在上面的代码中没有文件的完整路径 . 如果需要绝对路径,可以使用名为 _getfullpathnameos.path 模块的另一个函数,将从 os.listdir() 获得的文件作为参数 . 还有其他方法可以获得完整路径,我们稍后会检查(我更换了,如mexmex所建议,_getfullpathname和 abspath ) .

    >>> import os
    >>> files_path = [os.path.abspath(x) for x in os.listdir()]
    >>> files_path
    ['F:\\documenti\applications.txt', 'F:\\documenti\collections.txt']
    

    使用walk获取所有子目录中文件类型的完整路径名

    我发现这对于在许多目录中查找内容非常有用,它帮助我找到了一个我不记得名字的文件:

    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 ".docx" in file:
                print(os.path.join(r, file))
    

    os.listdir(): get files in the current directory (Python 2)

    在Python 2中,如果您想要当前目录中的文件列表,则必须将参数设置为“ . ” . 或os.listdir方法中的os.getcwd() .

    >>> import os
    >>> arr = os.listdir('.')
    >>> arr
    ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']
    

    进入目录树

    >>> # Method 1
    >>> x = os.listdir('..')
    
    # Method 2
    >>> x= os.listdir('/')
    

    获取文件:特定目录中的os.listdir()(Python 2和3)

    >>> import os
    >>> arr = os.listdir('F:\\python')
    >>> arr
    ['$RECYCLE.BIN', 'work.txt', '3ebooks.txt', 'documents']
    

    使用os.listdir()获取特定子目录的文件

    import os
    
    x = os.listdir("./content")
    

    os.walk(' . ') - 当前目录

    >>> import os
    >>> arr = next(os.walk('.'))[2]
    >>> arr
    ['5bs_Turismo1.pdf', '5bs_Turismo1.pptx', 'esperienza.txt']
    

    glob模块 - 所有文件

    import glob
    print(glob.glob("*"))
    
    out:['content', 'start.py']
    

    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)
    
    >output
    
    F:\\_python\\dict_class.py
    F:\\_python\\programmi.txt
    

    next(os.walk('F:') - 获取完整路径 - 列表理解

    >>> [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 - get full path - all files in sub dirs

    x = [os.path.join(r,file) for r,d,f in os.walk("F:\\_python") for file in f]
    
    >>>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")]
    >>> print(arr_txt)
    ['work.txt', '3ebooks.txt']
    

    glob - 只获取txt文件

    >>> import glob
    >>> x = glob.glob("*.txt")
    >>> x
    ['ale.txt', 'alunni2015.txt', 'assenze.text.txt', 'text2.txt', 'untitled.txt']
    

    使用glob获取文件的完整路径

    如果我需要文件的绝对路径:

    >>> from path import path
    >>> from glob import glob
    >>> x = [path(f).abspath() for f in glob("F:\*.txt")]
    >>> for f in x:
    ...  print(f)
    ...
    F:\acquistionline.txt
    F:\acquisti_2018.txt
    F:\bootstrap_jquery_ecc.txt
    

    其他使用glob

    如果我想要目录中的所有文件:

    >>> x = glob.glob("*")
    

    使用os.path.isfile来避免列表中的目录

    import os.path
    listOfFiles = [f for f in os.listdir() if os.path.isfile(f)]
    print(listOfFiles)
    
    > output
    
    ['a simple game.py', 'data.txt', 'decorator.py']
    

    使用pathlib(Python 3.4)

    import pathlib
    
    >>> flist = []
    >>> for p in pathlib.Path('.').iterdir():
    ...  if p.is_file():
    ...   print(p)
    ...   flist.append(p)
    ...
    error.PNG
    exemaker.bat
    guiprova.mp3
    setup.py
    speak_gui2.py
    thumb.PNG
    

    如果你想使用列表理解

    >>> flist = [p for p in pathlib.Path('.').iterdir() if p.is_file()]
    

    *您也可以使用pathlib.Path()而不是pathlib.Path(“ . ”)

    在pathlib.Path()中使用glob方法

    import pathlib
    
    py = pathlib.Path().glob("*.py")
    for file in py:
        print(file)
    

    输出:

    stack_overflow_list.py
    stack_overflow_list_tkinter.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)
    
    >>> y
    ['append_to_list.py', 'data.txt', 'data1.txt', 'data2.txt', 'data_180617', 'os_walk.py', 'READ2.py', 'read_data.py', 'somma_defaltdic.py', 'substitute_words.py', 'sum_data.py', 'data.txt', 'data1.txt', 'data_180617']
    

    只获取带有next的文件并进入目录

    >>> import os
    >>> x = next(os.walk('F://python'))[2]
    >>> x
    ['calculator.bat','calculator.py']
    

    只获取带有next的目录并进入目录

    >>> import os
    >>> next(os.walk('F://python'))[1] # for the current dir use ('.')
    ['python3','others']
    

    使用walk获取所有子目录名称

    >>> for r,d,f in os.walk("F:\_python"):
    ...  for dirs in d:
    ...   print(dirs)
    ...
    .vscode
    pyexcel
    pyschool.py
    subtitles
    _metaprogramming
    .ipynb_checkpoints
    

    来自Python 3.5的

    os.scandir()

    >>> import os
    >>> x = [f.name for f in os.scandir() if f.is_file()]
    >>> x
    ['calculator.bat','calculator.py']
    
    # 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)
    ...
    ebookmaker.py
    error.PNG
    exemaker.bat
    guiprova.mp3
    setup.py
    speakgui4.py
    speak_gui2.py
    speak_gui3.py
    thumb.PNG
    >>>
    

    例如1:子目录中有多少个文件?

    在此示例中,我们查找包含在所有目录及其子目录中的文件数 .

    import os
    
    def count(dir, counter=0):
        "returns number of files in dir and subdirs"
        for pack in os.walk(dir):
            for f in pack[2]:
                counter += 1
        return dir + " : " + str(counter) + "files"
    
    print(count("F:\\python"))
    
    > output
    
    >'F:\\\python' : 12057 files'
    

    例2:如何将目录中的所有文件复制到另一个目录?

    一个脚本,用于在计算机中查找所有类型的文件(默认值:pptx)并将其复制到新文件夹中 .

    import os
    import shutil
    from path import path
    
    destination = "F:\\file_copied"
    # os.makedirs(destination)
    
    def copyfile(dir, filetype='pptx', counter=0):
        "Searches for pptx (or other - pptx is the default) files and copies them"
        for pack in os.walk(dir):
            for f in pack[2]:
                if f.endswith(filetype):
                    fullpath = pack[0] + "\\" + f
                    print(fullpath)
                    shutil.copy(fullpath, destination)
                    counter += 1
        if counter > 0:
            print("------------------------")
            print("\t==> Found in: `" + dir + "` : " + str(counter) + " files\n")
    
    for dir in os.listdir():
        "searches for folders that starts with `_`"
        if dir[0] == '_':
            # copyfile(dir, filetype='pdf')
            copyfile(dir, filetype='txt')
    
    
    > Output
    
    _compiti18\Compito Contabilità 1\conti.txt
    _compiti18\Compito Contabilità 1\modula4.txt
    _compiti18\Compito Contabilità 1\moduloa4.txt
    ------------------------
    ==> Found in: `_compiti18` : 3 files
    

    例如3:如何获取txt文件中的所有文件

    如果您要创建包含所有文件名的txt文件:

    import os
    mylist = ""
    with open("filelist.txt", "w", encoding="utf-8") as file:
        for eachfile in os.listdir():
            mylist += eachfile + "\n"
        file.write(mylist)
    

    示例:txt包含硬盘的所有文件

    """We are going to save a txt file with all the files in your directory.
    We will use the function walk()
    
    """
    
    import os
    
    # see all the methods of os
    # print(*dir(os), sep=", ")
    listafile = []
    percorso = []
    with open("lista_file.txt", "w", encoding='utf-8') as testo:
        for root, dirs, files in os.walk("D:\\"):
            for file in files:
                listafile.append(file)
                percorso.append(root + "\\" + file)
                testo.write(file + "\n")
    listafile.sort()
    print("N. of files", len(listafile))
    with open("lista_file_ordinata.txt", "w", encoding="utf-8") as testo_ordinato:
        for file in listafile:
            testo_ordinato.write(file + "\n")
    
    with open("percorso.txt", "w", encoding="utf-8") as file_percorso:
        for file in percorso:
            file_percorso.write(file + "\n")
    
    os.system("lista_file.txt")
    os.system("lista_file_ordinata.txt")
    os.system("percorso.txt")
    

    一个文本文件中C:\的所有文件

    这是以前代码的较短版本 . 如果需要从其他位置开始,请更改文件夹从哪里开始查找文件 . 此代码在我的计算机上生成一个50 MB的文本文件,其中包含少于500.000行,文件包含完整路径 .

    import os
    
    with open("file.txt", "w", encoding="utf-8") as filewrite:
        for r, d, f in os.walk("C:\\"):
            for file in f:
                filewrite.write(f"{r + file}\n")
    

    用于搜索特定类型文件的函数

    进口口

    def searchfiles(extension='.ttf'):
        "Create a txt file with all the file of a type"
        with open("file.txt", "w", encoding="utf-8") as filewrite:
            for r, d, f in os.walk("C:\\"):
                for file in f:
                    if file.endswith(extension):
                        filewrite.write(f"{r + file}\n")
    
    # looking for ttf file (fonts)
    searchfiles('ttf')
    
  • 61

    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()]
    
  • 21

    我假设您的所有文件都是 *.txt 格式,并存储在路径为 data/ 的目录中 .

    可以使用 pythonglob模块列出目录的所有文件,并按以下方式将它们添加到名为 fnames 的列表中:

    import glob
    
    fnames = glob.glob("data/*.txt")  #fnames: list data type
    
  • 4

    我将提供一个样本一个衬管,其中可以提供源路径和文件类型作为输入 . 该代码返回带有csv扩展名的文件名列表 . 使用 . 以防需要返回所有文件 . 这也将递归扫描子目录 .

    [y for x in os.walk(sourcePath) for y in glob(os.path.join(x[0], '*.csv'))]

    根据需要修改文件扩展名和源路径 .

  • 3

    初步说明

    • 尽管问题文本中的文件和目录术语之间存在明显区别,但有些人可能认为目录实际上是特殊文件

    • 语句:“目录的所有文件”可以用两种方式解释:

    • 所有 direct (或1级)后代 only

    • 整个目录树中的所有后代(包括子目录中的后代)

    • 当问到这个问题时,我认为Python 2 是LTS版本,但是代码示例将由Python运行 3.5 )(我会尽可能保持它们与Python 2兼容;同样,任何代码属于我要发布的Python来自 v3.5.4 - 除非另有说明) . 这与问题中的另一个关键字有关:“将它们添加到 list ”:

    • 在Python 2之前的版本中,序列(iterables)主要由列表(元组,集合,......)表示

    • 在Python 2.2中,引入了 generator[Python.Wiki]: Generators)的概念 - 由[Python 3]: The yield statement提供 - . 随着时间的推移,生成器对应物开始出现用于返回/使用列表的函数

    • 在Python 3中,生成器是默认行为

    • 不确定返回列表是否仍然是必需的(或者生成器也可以这样做),但是将生成器传递给列表构造函数,将创建一个列表(并且还使用它) . 以下示例说明了[Python 3]: map(function, iterable, ...)的差异

    导入系统
    sys.version
    '2.7.10(默认,2016年3月8日,15:02:46)[MSC v.1600 64 bit(AMD64)]'
    m = map(lambda x:x,[1,2,3])#只是一个虚拟lambda函数
    m,类型(m)
    ([1,2,3],<type'list'>)
    len(m)
    3

    导入系统
    sys.version
    '3.5.4(v3.5.4:3f56838,2017年8月8日,02:17:05)[MSC v.1900 64 bit(AMD64)]'
    m = map(lambda x:x,[1,2,3])
    m,类型(m)
    (< Map 对象位于0x000001B4257342B0>,<class'map'>)
    len(m)
    追溯(最近的电话持续):
    在<module>中的文件“<stdin>”,第1行
    TypeError:'map'类型的对象没有len()
    lm0 = list(m)#从生成器构建一个列表
    lm0,类型(lm0)
    ([1,2,3],<class'list'>)

    lm1 = list(m)#从同一个生成器构建一个列表
    lm1,type(lm1)#立即清空列表 - 生成器已消耗
    ([],<class'list'>)

    • 示例将基于名为root_dir的目录,具有以下结构(此示例适用于Win,但我在Lnx上也使用相同的树):

    E:\ Work \ Dev \ StackOverflow \ q003207219> tree / f“root_dir”
    卷工作的文件夹PATH列表
    卷序列号为00000029 3655:6FED
    E:\工作\ DEV \计算器\ Q003207219 \ ROOT_DIR
    | file0
    | file1
    |
    --- DIR0
    | --- dir00
    | | | file000
    | | |
    | | --- dir000
    | | file0000
    | |
    | --- dir01
    | | file010
    | | file011
    | |
    | --- dir02
    | --- dir020
    | --- dir0200
    --- DIR1
    | file10
    | file11
    | file12
    |
    --- DIR2
    | | file20
    | |
    | --- dir20
    | file200
    |
    --- DIR3

    解决方案

    程序化方法:

    返回一个列表,其中包含path给出的目录中的条目名称 . 该列表按任意顺序排列,不包括特殊条目' . '和'..'......

    导入操作系统
    root_dir =“root_dir”#相对于当前目录的路径(os.getcwd())

    os.listdir(root_dir)#列出root_dir中的所有项目
    ['dir0','dir1','dir2','dir3','file0','file1']

    [os.listdir(root_dir)中项目的项目,如果os.path.isfile(os.path.join(root_dir,item))]#过滤项目并仅保留文件(去掉目录)
    ['file0','file1']

    一个更详细的例子(code_os_listdir.py):

    import os
    from pprint import pformat
    
    
    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():
        root_dir = "root_dir"
        ret0 = get_dir_content(root_dir, include_folders=True, recursive=True, prepend_folder_name=True)
        lret0 = list(ret0)
        print(ret0, len(lret0), pformat(lret0))
        ret1 = get_dir_content_old(root_dir, include_folders=False, recursive=True, prepend_folder_name=False)
        print(len(ret1), pformat(ret1))
    
    
    if __name__ == "__main__":
        main()
    

    Notes

    • 有两种实现方式:

    • 使用生成器的一个(当然这里似乎没用,因为我立即将结果转换为列表)

    • 经典之一(函数名以 _old 结尾)

    • 使用递归(进入子目录)

    • 对于每个实现,有两个功能:

    • 以下划线( _ )开头的那个:"private"(不应该直接调用) - 完成所有工作

    • public one(前一个包装器):它只是从返回的条目中剥离初始路径(如果需要) . 它是我在这一点上唯一能想到的想法

    • 在性能方面,生成器通常要快一点(考虑创建和迭代时间),但我没有知道性能如何友好

    • 使用参数进行播放以获得不同的结果

    Output

    (py35x64_test)E:\ Work \ Dev \ StackOverflow \ q003207219>“e:\ Work \ Dev \ VEnvs \ py35x64_test \ Scripts \ python.exe”“code_os_listdir.py”
    <generator object get_dir_content at 0x000001BDDBB3DF10> 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 \文件1']
    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',
    “文件1”]

    返回与path给出的目录中的条目对应的os.DirEntry对象的迭代器 . 条目以任意顺序产生,特殊条目' . '和'..'不包括在内 . 使用scandir()而不是listdir()可以显着提高还需要文件类型或文件属性信息的代码的性能,因为os.DirEntry对象在操作系统扫描目录时提供此信息 . 所有os.DirEntry方法都可以执行系统调用,但是is_dir()和is_file()通常只需要对符号链接进行系统调用; os.DirEntry.stat()总是需要在Unix上进行系统调用,但在Windows上只需要一个符号链接 .

    导入操作系统
    root_dir = os.path.join(“ . ”,“root_dir”)#明确地在当前目录之前
    root_dir
    '\ ROOT_DIR'

    scandir_iterator = os.scandir(root_dir)
    scandir_iterator
    <nt.ScandirIterator对象位于0x00000268CF4BC140>
    [scandir_iterator中项目的项目路径]
    [' . \ root_dir \ dir0',' . \ root_dir \ dir1',' . \ root_dir \ dir2',' . \ root_dir \ dir3',' . \ root_dir \ file0' ,' . \ root_dir \ file1']

    [scandir_iterator中项目的项目路径]#将产生一个空列表,因为它被前一次迭代消耗(由列表自动执行)理解)
    []

    scandir_iterator = os.scandir(root_dir)#重新初始化生成器
    for scandir_iterator中的项目:
    ...如果os.path.isfile(item.path):
    ... print(item.name)
    ...
    file0
    文件1

    Notes

    通过从上到下或从下到上走树来生成目录树中的文件名 . 对于以目录top(包括top本身)为根的树中的每个目录,它会产生一个3元组(dirpath,dirnames,filenames) .

    导入操作系统
    root_dir = os.path.join(os.getcwd(),“root_dir”)#指定完整路径
    root_dir
    'E:\ \工作\开发StackOverflow的\ \ q003207219 ROOT_DIR'

    walk_generator = os.walk(root_dir)
    root_dir_entry = next(walk_generator)#第一个条目对应根目录(作为参数传递)
    root_dir_entry
    ('E:\ Work \ Dev \ StackOverflow \ q003207219 \ root_dir',['dir0','dir1','dir2','dir3'],['file0','file1'])

    root_dir_entry [1] root_dir_entry [2]#在单个列表中显示目录和文件(直接后代)
    ['dir0','dir1','dir2','dir3','file0','file1']

    [os.path.join(root_dir_entry [0],item)for root_dir_entry中的项目[1] root_dir_entry [2]]#按完整路径显示上一个列表中的所有条目
    ['E:\ Work \ Dev \ StackOverflow \ q003207219 \ root_dir \ dir0','E:\ Work \ Dev \ StackOverflow \ q003207219 \ root_dir \ dir1','E: \工作\ Dev \ StackOverflow \ q003207219 \ root_dir \ dir2','E:\工作\ Dev \ StackOverflow \ q003207219 \ root_dir \ dir3','E:\工作\ \ Dev \ StackOverflow \ q003207219 \ root_dir \ file0','E:\ Work \ Dev \ StackOverflow \ q003207219 \ root_dir \ file1']

    for walk_generator中的条目:#显示其余元素(对应于每个子目录)
    ...打印(条目)
    ...
    ('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',[],[])

    Notes

    返回与路径名匹配的可能为空的路径名列表,路径名必须是包含路径规范的字符串 . pathname可以是绝对的(如/usr/src/Python-1.5/Makefile)或relative(如../../Tools//.gif),也可以包含shell样式的通配符 . 结果中包含损坏的符号链接(如在shell中) . ...在版本3.5中更改:使用“**”支持递归globs .

    import glob,os
    wildcard_pattern =“*”
    root_dir = os.path.join(“root_dir”,wildcard_pattern)#匹配每个文件/目录名称
    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 glob_list中的项目#从开始处删除目录名称和路径分隔符
    ['dir0','dir1','dir2','dir3','file0','file1']

    for glob.iglob(root_dir“*”,recursive = True)中的条目:
    ...打印(条目)
    ...
    ROOT_DIR
    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 \文件1

    Notes

    导入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()
    真正

    [root_dir_instance.glob(“*”)中项目的[item.name]#通配符搜索所有直接后代
    ['dir0','dir1','dir2','dir3','file0','file1']

    [os.path.join(item.parent.name,item.name)for root_dir_instance.glob(“*”)中的项目,如果不是item.is_dir()]#仅显示文件的路径(包括父项)
    ['root_dir \ file0','root_dir \ file1']

    Notes

    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
    

    ctypes是Python的外部函数库 . 它提供C兼容的数据类型,并允许在DLL或共享库中调用函数 . 它可以用于在纯Python中包装这些库 .

    code_ctypes.py:

    #!/usr/bin/env python3
    
    import sys
    from ctypes import Structure, \
        c_ulonglong, c_longlong, c_ushort, c_ubyte, c_char, c_int, \
        CDLL, POINTER, \
        create_string_buffer, get_errno, set_errno, cast
    
    
    DT_DIR = 4
    DT_REG = 8
    
    char256 = c_char * 256
    
    
    class LinuxDirent64(Structure):
        _fields_ = [
            ("d_ino", c_ulonglong),
            ("d_off", c_longlong),
            ("d_reclen", c_ushort),
            ("d_type", c_ubyte),
            ("d_name", char256),
        ]
    
    LinuxDirent64Ptr = POINTER(LinuxDirent64)
    
    libc_dll = this_process = CDLL(None, use_errno=True)
    # ALWAYS set argtypes and restype for functions, otherwise it's UB!!!
    opendir = libc_dll.opendir
    readdir = libc_dll.readdir
    closedir = libc_dll.closedir
    
    
    def get_dir_content(path):
        ret = [path, list(), list()]
        dir_stream = opendir(create_string_buffer(path.encode()))
        if (dir_stream == 0):
            print("opendir returned NULL (errno: {:d})".format(get_errno()))
            return ret
        set_errno(0)
        dirent_addr = readdir(dir_stream)
        while dirent_addr:
            dirent_ptr = cast(dirent_addr, LinuxDirent64Ptr)
            dirent = dirent_ptr.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)
            dirent_addr = readdir(dir_stream)
        if get_errno():
            print("readdir returned NULL (errno: {:d})".format(get_errno()))
        closedir(dir_stream)
        return ret
    
    
    def main():
        print("{:s} on {:s}\n".format(sys.version, sys.platform))
        root_dir = "root_dir"
        entries = get_dir_content(root_dir)
        print(entries)
    
    
    if __name__ == "__main__":
        main()
    

    Notes

    • 它从libc加载三个函数(在当前进程中加载)并调用它们(有关更多详细信息,请检查[SO]: How do I check whether a file exists without exceptions? (@CristiFati's answer) - 项目 #4. 的最后一个注释) . 这将使这种方法非常接近Python / C边缘

    • LinuxDirent64是来自我机器的[man7]: dirent.h(0P)(也就是DT_常量)的struct dirent64的ctypes表示形式:Ubtu 16 x64(4.10.0-40-generic和libc6-dev:amd64) . 在其他版本/版本上,结构定义可能不同,如果是,则应更新ctypes别名,否则它将产生 Undefined Behavior

    • 它返回 os.walk 's format. I didn' t中的数据以使其递归,但从现有代码开始,这将是一项相当简单的任务

    • 在Win上一切都是可行的,数据(库,函数,结构,常量,......)不同

    Output

    [cfati @ cfati-ubtu16x64-0:〜/ Work / Dev / StackOverflow / q003207219]> ./code_ctypes.py
    3.5.2(默认,2018年11月12日,13:43:14)
    [GCC 5.4.0 20160609]在linux上

    ['root_dir',['dir2','dir1','dir3','dir0'],['file1','file0']]

    使用Windows Unicode API检索匹配文件名列表 . API FindFirstFileW / FindNextFileW / Find关闭函数的接口 .

    import os,win32file,win32con
    root_dir =“root_dir”
    wildcard =“*”
    root_dir_wildcard = os.path.join(root_dir,wildcard)
    entry_list = win32file.FindFilesW(root_dir_wildcard)
    len(entry_list)#不要显示整个内容,因为它太长了
    8
    [entry_-entry for entry_list] ##仅显示条目名称
    [' . ','..','dir0','dir1','dir2','dir3','file0','file1']

    [entry [-2]表示entry_list中的条目,如果entry [0]&win32con.FILE_ATTRIBUTE_DIRECTORY且条目[-2]不在(“ . ”,“..”)中]#过滤条目并仅显示目录名称(除了自己和父母)
    ['dir0','dir1','dir2','dir3']

    [os.path.join(root_dir,entry [-2])用于entry_list中的条目,如果entry [0]&(win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_ATTRIBUTE_ARCHIVE)]#仅显示文件“完整”名称
    ['root_dir \ file0','root_dir \ file1']

    Notes

    Notes

    • 代码是可移植的(除了针对特定区域的地方 - 标记的)或交叉:

    • 平台(Ux,Win,)

    • Python版(2,3)

    • 在上述变体中使用了多种路径样式(绝对,亲属),以说明所使用的“工具”在这个方向上是灵活的

    • os.listdiros.scandir 使用opendir / readdir / closedir([MS.Docs]: FindFirstFileW function / [MS.Docs]: FindNextFileW function / [MS.Docs]: FindClose function)(通过[GitHub]: python/cpython - (master) cpython/Modules/posixmodule.c

    • win32file.FindFilesW 也使用那些(Win特定的)函数(通过[GitHub]: mhammond/pywin32 - (master) pywin32/win32/src/win32file.i

    • _get_dir_content(来自点 #1. )可以使用任何这些方法实现(有些需要更多工作,更少一些)

    • 可以完成一些高级过滤(而不仅仅是文件与目录):例如include_folders参数可以替换为另一个(例如filter_func),它将是一个以路径作为参数的函数: filter_func=lambda x: True (这不会删除任何东西)和_get_dir_content里面的东西: if not filter_func(entry_with_path): continue (如果函数失败了一个输入,它将被跳过),但代码越复杂,执行所需的时间就越长

    • Nota bene! 由于使用了递归,我必须提到我在我的笔记本电脑上进行了一些测试(Win 10 x64),与此问题完全无关,并且当递归级别达到(990 .. 1000)范围内的某个值时(递归限制) - 1000(默认)),我得到StackOverflow :) . 如果目录树超过了该限制(我不是FS专家,所以我不知道这是否可能),这可能是一个问题 .
      我还必须提到我没有尝试增加recursionlimit因为我没有该领域的经验(在不得不在操作系统级别增加堆栈之前我可以增加多少),但理论上如果dir深度大于最高可能,则总会有失败的可能性recursionlimit(在那台机器上)

    • 代码示例仅用于演示目的 . 这意味着我没有认为有任何 try / except / else / finally 块,所以代码不健壮(原因是:尽可能保持简单和简短) . 对于 生产环境 ,还应添加错误处理

    其他方法:

    • 仅将Python用作包装器

    • 一切都是使用其他技术完成的

    • 该技术是从Python调用的

    • 我所知道的最着名的风格是我称之为系统管理员的方法:

    • 使用Python(或任何编程语言)来执行shell命令(并解析其输出)

    • 有些人认为这是一个整洁的黑客

    • 我认为它更像是一个蹩脚的解决方法(获得),因为操作本身是从shell(在这种情况下为cmd)执行的,因此与Python没有任何关系 .

    • 过滤( grep / findstr )或输出格式可以在双方完成,但我不会坚持它 . 另外,我故意使用 os.system 而不是 subprocess.Popen .

    (py35x64_test)E:\ Work \ Dev \ StackOverflow \ q003207219>“e:\ Work \ Dev \ VEnvs \ py35x64_test \ Scripts \ python.exe”-c“import os; os.system(\”dir / b root_dir \ “)”
    DIR0
    DIR1
    DIR2
    DIR3
    file0
    文件1

    通常,这种方法应该被避免,因为如果某些命令输出格式在OS版本/风格之间略有不同,则解析代码也应该被调整;更不用说语言环境之间的差异了) .

  • 414
    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
    
  • 1

    Getting Full File Paths From a Directory and All Its Subdirectories

    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

  • 9
    # -** coding: utf-8 -*-
    import os
    import traceback
    
    print '\n\n'
    
    def start():
        address = "/home/ubuntu/Desktop"
        try:
            Folders = []
            Id = 1
            for item in os.listdir(address):
                endaddress = address + "/" + item
                Folders.append({'Id': Id, 'TopId': 0, 'Name': item, 'Address': endaddress })
                Id += 1         
    
                state = 0
                for item2 in os.listdir(endaddress):
                    state = 1
                if state == 1: 
                    Id = FolderToList(endaddress, Id, Id - 1, Folders)
            return Folders
        except:
            print "___________________________ ERROR ___________________________\n" + traceback.format_exc()
    
    def FolderToList(address, Id, TopId, Folders):
        for item in os.listdir(address):
            endaddress = address + "/" + item
            Folders.append({'Id': Id, 'TopId': TopId, 'Name': item, 'Address': endaddress })
            Id += 1
    
            state = 0
            for item in os.listdir(endaddress):
                state = 1
            if state == 1: 
                Id = FolderToList(endaddress, Id, Id - 1, Folders)
        return Id
    
    print start()
    
  • 5

    这是我的通用功能 . 它返回文件路径而不是文件名列表,因为我发现它更有用 . 它有一些可选参数,使其具有多种功能 . 例如,我经常使用像 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)]
    

相关问题