【问题标题】:Copying files in python using shutil使用shutil在python中复制文件
【发布时间】:2018-09-12 18:14:01
【问题描述】:
I have the following directory structure:

 -mailDir
     -folderA
         -sub1
         -sub2
         -inbox
            -1.txt
            -2.txt
            -89.txt
            -subInbox
            -subInbox2
     -folderB
         -sub1
         -sub2
         -inbox
            -1.txt
            -2.txt
            -200.txt
            -577.txt

目的是将收件箱文件夹下的所有txt文件复制到另一个文件夹中。 为此,我尝试了以下代码

import os
from os import path
import shutil

rootDir = "mailDir"
destDir = "destFolder"

eachInboxFolderPath = []
for root, dirs, files in os.walk(rootDir):
    for dirName in dirs:
        if(dirName=="inbox"):
            eachInboxFolderPath.append(root+"\\"+dirName)

for ii in eachInboxFolderPath:
    for i in os.listdir(ii):
        shutil.copy(path.join(ii,i),destDir)

如果收件箱目录只有 .txt 文件,那么上面的代码可以正常工作。由于文件夹A目录下的收件箱文件夹还有其他子目录以及.txt文件,因此代码返回权限被拒绝错误。我的理解是 shutil.copy 不允许复制文件夹。

目的是仅将每个收件箱文件夹中的 txt 文件复制到其他位置。如果不同收件箱文件夹中的文件名相同,我必须保留两个文件名。在这种情况下我们如何改进代码?请注意,除 .txt 之外的所有其他文件都只是文件夹。

【问题讨论】:

  • 我建议使用os.path.isfile 或os.path.isdir 函数来检查一个项目是否是一个目录/文件夹。然后,您可以避免尝试复制该文件夹。 docs.python.org/3.6/library/os.path.html
  • 这行得通。如果文件名相同,则在我必须保留这两个文件时它会被覆盖。我们如何做到这一点?
  • 您必须重命名一个(或两个),因为(显然)两个同名文件不能同时存在于同一路径中。所以,我建议使用shutil.copyfile 而不是.copy。您需要首先检查目标文件夹中是否存在该文件。

标签: python file shutil


【解决方案1】:

一个简单的解决方案是使用字符串endswith() 方法过滤任何没有.txt 扩展名的i。

import os
from os import path
import shutil

rootDir = "mailDir"
destDir = "destFolder"

eachInboxFolderPath = []
for root, dirs, files in os.walk(rootDir):
    for dirName in dirs:
        if(dirName=="inbox"):
            eachInboxFolderPath.append(root+"\\"+dirName)

for ii in eachInboxFolderPath:
    for i in os.listdir(ii):
         if i.endswith('.txt'):
            shutil.copy(path.join(ii,i),destDir)

这应该忽略使用os.listdir(ii) 找到的所有文件夹和非txt 文件。我相信这就是您正在寻找的。​​p>

【讨论】:

  • 在实际场景中,文件没有附加 .txt 扩展名。我可以看到 1、2 等。我把 .txt 放在这里只是为了让它更清楚。对不起,如果这会误导。
  • 应该可以,但可能更适合使用os.path.isfile 或os.path.isdir 函数:docs.python.org/3.6/library/os.path.html
【解决方案2】:

只记得我曾经写过几个文件来解决这个确切的问题。可以找到源代码here on my Github。

简而言之,这里有两个感兴趣的函数:

  • list_files(loc, return_dirs=False, return_files=True, recursive=False, valid_exts=None)
  • copy_files(loc, dest, rename=False)

对于您的情况,您可以将这些函数复制并粘贴到您的项目中,然后像这样修改copy_files:

def copy_files(loc, dest, rename=False):
    # get files with full path
    files = list_files(loc, return_dirs=False, return_files=True, recursive=True, valid_exts=('.txt',))

    # copy files in list to dest
    for i, this_file in enumerate(files):
        # change name if renaming
        if rename:
            # replace slashes with hyphens to preserve unique name
            out_file = sub(r'^./', '', this_file)
            out_file = sub(r'\\|/', '-', out_file)
            out_file = join(dest, out_file)
            copy(this_file, out_file)
            files[i] = out_file
        else:
            copy(this_file, dest)

    return files

那就这样称呼吧:

copy_files('mailDir', 'destFolder', rename=True)

重命名方案可能不是您想要的,但它至少不会覆盖您的文件。我相信这应该可以解决您的所有问题。

【讨论】:

    【解决方案3】:

    给你:

    import os
    from os import path
    import shutil
    
    destDir = '<absolute-path>'
    for root, dirs, files in os.walk(os.getcwd()):
        # Filter out only '.txt' files.
        files = [f for f in files if f.endswith('.txt')]
        # Filter out only 'inbox' directory.
        dirs[:] = [d for d in dirs if d == 'inbox']
    
    for f in files:
        p = path.join(root, f)
        # print p
        shutil.copy(p, destDir)
    

    快速简单。

    抱歉,我忘记了其中的部分,您还需要唯一的文件名。上述解决方案仅适用于单个收件箱文件夹中的不同文件名。

    要从多个收件箱复制文件并在目标文件夹中具有唯一名称,您可以尝试以下操作:

    import os
    from os import path
    import shutil
    
    sourceDir = os.getcwd()
    fixedLength = len(sourceDir)
    
    destDir = '<absolute-path>'
    
    filteredFiles = []
    
    for root, dirs, files in os.walk(sourceDir):
        # Filter out only '.txt' files in all the inbox directories.
        if root.endswith('inbox'):
            # here I am joining the file name to the full path while filtering txt files
            files = [path.join(root, f) for f in files if f.endswith('.txt')]
            # add the filtered files to the main list
            filteredFiles.extend(files)
    
    # making a tuple of file path and file name
    filteredFiles = [(f, f[fixedLength+1:].replace('/', '-')) for f in filteredFiles]
    
    for (f, n) in filteredFiles:
        print 'copying file...', f
        # copying from the path to the dest directory with specific name
        shutil.copy(f, path.join(destDir, n))
    
    print 'copied', str(len(filteredFiles)), 'files to', destDir
    

    如果您需要复制所有文件而不仅仅是txt文件,那么只需将条件f.endswith('.txt')更改为os.path.isfile(f),同时过滤掉文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-29
      • 1970-01-01
      • 2015-12-24
      • 2018-07-24
      • 2021-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多