【问题标题】:Scan files recursively and delete empty directories in python递归扫描文件并删除python中的空目录
【发布时间】:2014-03-26 21:50:09
【问题描述】:

我有以下结构:

Dir 1
|___Dir 2
   |___file 1
   |___file 2...
Dir 3
|___Dir 4
   |___file 3...

我希望能够递归地找到每个文件,以我自己的方式处理文件,一旦完成,删除文件,移动到下一个。然后,如果目录为空,也将其删除,直到没有任何内容为止。

只是不知道如何继续。

这就是我所拥有的:

for root, dirs, files in os.walk(dir):
    path = root.split('/')
    for file in files:
        file = os.path.join(root, file)
        process_file(file)
        os.remove(file)

这很好,但我想删除子目录,如果且只有它们是空的。

【问题讨论】:

  • 你试过什么?您使用什么包来浏览/导航文件树?
  • 嗨。您似乎对 SO 很陌生。如果您希望人们帮助您,我鼓励您知道向我们展示您迄今为止编写的代码,我们将在此基础上尝试为您提供帮助。
  • 执行os.walk 获取所有文件,执行os.path.join 获取完整文件路径以进行处理。最终删除根(这将删除它下面的所有内容)
  • 我宁愿不删除子目录,除非它们是空的。所以如果一个文件不能正确处理,我想把它留在那里,它是子目录。从根目录删除不是我想要的。

标签: python file recursion directory delete-file


【解决方案1】:

看来聚会迟到了。不过,这里有另一个可以帮助初学者的解决方案。

进口

import os

from contextlib import suppress

包含在适当的函数中

# Loop for processing files
for root, _, files in os.walk(dir):
    path = root.split('/')
    for file in files:
        file = os.path.join(root, file)

        # Assuming process_file() returns True on success
        if process_file(file):
            os.remove(file)

包含在适当的函数中

# Loop for deleting empty directories
for root, _, _ in os.walk(dir):
        # Ignore directory not empty errors; nothing can be done about it if we want
        # to retain files that failed to be processsed. The entire deletion would
        # hence be silent.
        with suppress(OSError):
            os.removedirs(root)

【讨论】:

    【解决方案2】:

    这是我认为有效的另一种解决方案。当然,使用os.scandir可以提高效率。

    首先,我定义了一个通用的rec_rmdir函数(递归rmdir),它递归地浏览目录树。

    • 该函数首先处理每个文件和每个子目录。
    • 然后它会尝试删除当前目录。
    • preserve 标志用于保留根目录。

    算法是经典的Depth-first search

    import os
    import stat
    
    
    def rec_rmdir(root, callback, preserve=True):
        for path in (os.path.join(root, p) for p in os.listdir(root)):
            st = os.stat(path)
            if stat.S_ISREG(st.st_mode):
                callback(path)
            elif stat.S_ISDIR(st.st_mode):
                rec_rmdir(path, callback, preserve=False)
        if not preserve:
            try:
                os.rmdir(root)
            except IOError:
                pass
    

    然后,很容易定义一个处理文件并将其删除的函数。

    def process_file_and_remove(path):
        # process the file
        # ...
        os.remove(path)
    

    经典用法:

    rec_rmdir("/path/to/root", process_file_and_remove)
    

    【讨论】:

      【解决方案3】:
      import os
      
      #Top level of tree you wish to delete empty directories from.
      currentDir = r'K:\AutoCAD Drafting Projects\USA\TX\Image Archive'
      
      index = 0
      
      for root, dirs, files in os.walk(currentDir):
          for dir in dirs:
              newDir = os.path.join(root, dir)
              index += 1
              print str(index) + " ---> " + newDir
      
              try:
                  os.removedirs(newDir)
                  print "Directory empty! Deleting..."
                  print " "
              except:
                  print "Directory not empty and will not be removed"
                  print " "
      

      漂亮而简单。关键是在 try 语句下使用os.removedirs。它已经是递归的了。

      【讨论】:

        【解决方案4】:

        我意识到这篇文章比较老,添加一个额外的例子可能没有意义,但乍一看,我认为初学者比这里的其他一些人更容易掌握,因为没有加入,它只导入一个模块,它给出了如何使用一些内置函数 [open() & len()] 和新的 Python3 字符串格式化与 str.format 的很好的例子。它还显示了在 print() 函数中使用 file = filename 将内容填充到文件是多么简单。

        该脚本将使用 os.walk() 扫描根目录,检查目录和文件的长度,并根据找到的内容执行条件。它还增加一个计数器以确定使用的目录数和空目录数,并将信息输出到文件中。我在 Python 3.4 中编写了这个示例,它适用于我的目的。如果有人有改进逻辑的想法,请在 cmets 中发布,以便我们都可以学习解决问题的新视角。

        import os
        #declare the root directory
        root_dir = 'C:\\tempdir\\directory\\directory\\'
        #initialize the counters
        empty_count = 0
        used_count = 0
        #Set the file to write to. 'x' will indicate to create a new file and open it for writing
        outfile = open('C:\\tempdir\\directories.txt', 'x')
        for curdir, subdirs, files in os.walk(root_dir):
            if len(subdirs) == 0 and len(files) == 0: #check for empty directories. len(files) == 0 may be overkill
                empty_count += 1 #increment empty_count
                print('Empty directory: {}'.format(curdir), file = outfile) #add empty results to file
                os.rmdir(curdir) #delete the directory
            elif len(subdirs) > 0 and len(files) > 0: #check for used directories
                used_count += 1 #increment used_count
                print('Used directory: {}'.format(curdir), file = outfile) #add used results to file
        
        #add the counters to the file
        print('empty_count: {}\nused_count: {}'.format(empty_count, used_count), file = outfile) 
        outfile.close() #close the file
        

        【讨论】:

          【解决方案5】:

          这仅用于删除空目录并拉出单个目录文件。好像只回答了一部分问题,抱歉。

          我在最后添加了一个循环以继续尝试,直到它再也找不到为止。我让函数返回已删除目录的计数。

          我的访问被拒绝错误由 shutil.rmtree fails on Windows with 'Access is denied' 修复

          import os
          import shutil
          
          
          def onerror(func, path, exc_info):
              """
              Error handler for ``shutil.rmtree``.
          
              If the error is due to an access error (read only file)
              it attempts to add write permission and then retries.
          
              If the error is for another reason it re-raises the error.
          
              Usage : ``shutil.rmtree(path, ignore_errors=False, onerror=onerror)``
              """
              import stat
          
              if not os.access(path, os.W_OK):
                  # Is the error an access error ?
                  os.chmod(path, stat.S_IWUSR)
                  func(path)
              else:
                  raise
          
          
          def get_empty_dirs(path):
              # count of removed directories
              count = 0
              # traverse root directory, and list directories as dirs and files as files
              for root, dirs, files in os.walk(path):
                  try:
                      # if a directory is empty there will be no sub-directories or files
                      if len(dirs) is 0 and len(files) is 0:
                          print u"deleting " + root
                          # os.rmdir(root)
                          shutil.rmtree(root, ignore_errors=False, onerror=onerror)
                          count += 1
                      # if a directory has one file lets pull it out.
                      elif len(dirs) is 0 and len(files) is 1:
                          print u"moving " + os.path.join(root, files[0]) + u" to " + os.path.dirname(root)
                          shutil.move(os.path.join(root, files[0]), os.path.dirname(root))
                          print u"deleting " + root
                          # os.rmdir(root)
                          shutil.rmtree(root, ignore_errors=False, onerror=onerror)
                          count += 1
                  except WindowsError, e:
                      # I'm getting access denied errors when removing directory.
                      print e
                  except shutil.Error, e:
                      # Path your moving to already exists
                      print e
              return count
          
          
          def get_all_empty_dirs(path):
              # loop till break
              total_count = 0
              while True:
                  # count of removed directories
                  count = get_empty_dirs(path)
                  total_count += count
                  # if no removed directories you are done.
                  if count >= 1:
                      print u"retrying till count is 0, currently count is: %d" % count
                  else:
                      break
          
              print u"Total directories removed: %d" % total_count
              return total_count
          
          
          count = get_all_empty_dirs(os.getcwdu())  # current directory
          count += get_all_empty_dirs(u"o:\\downloads\\")  # other directory
          print u"Total of all directories removed: %d" % count
          

          【讨论】:

            【解决方案6】:

            好吧,我想这可以,但必须运行 os.walk...

            def get_files(src_dir):
            # traverse root directory, and list directories as dirs and files as files
                for root, dirs, files in os.walk(src_dir):
                    path = root.split('/')
                    for file in files:
                        process(os.path.join(root, file))
                                os.remove(os.path.join(root, file))
            
            def del_dirs(src_dir):
                for dirpath, _, _ in os.walk(src_dir, topdown=False):  # Listing the files
                    if dirpath == src_dir:
                        break
                    try:
                        os.rmdir(dirpath)
                    except OSError as ex:
                        print(ex)
            
            
            def main():
                get_files(src_dir)
                del_dirs(src_dir)
            
            
            if __name__ == "__main__":
                main()
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-11-30
              • 1970-01-01
              • 2011-12-31
              • 2013-12-05
              • 1970-01-01
              • 2014-06-21
              • 1970-01-01
              • 2013-06-25
              相关资源
              最近更新 更多