使用Shutil在python中复制文件

时间:2018-09-12 18:14:01

标签: python file shutil

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文件,则上述代码可以正常工作。由于folderA目录下的inbox文件夹具有其他子目录以及.txt文件,因此代码返回权限被拒绝错误。我了解的是shutil.copy不允许复制文件夹。

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

3 个答案:

答案 0 :(得分:2)

一个简单的解决方案是使用字符串endswith()方法来过滤所有不具有i扩展名的.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):
         if i.endswith('.txt'):
            shutil.copy(path.join(ii,i),destDir)

这应该忽略用os.listdir(ii)找到的所有文件夹和非txt文件。我相信这就是您想要的。

答案 1 :(得分:0)

只记得我曾经写过几个文件来解决这个确切的问题。您可以找到源代码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)

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

答案 2 :(得分:0)

您在这里:

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)