Копирование файлов в python с использованием shutil - PullRequest
0 голосов
/ 12 сентября 2018
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

Цель состоит в том, чтобы скопировать все текстовые файлы из папки «Входящие» в другую папку.Для этого я попробовал приведенный ниже код

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 имеет другой подкаталог, кроме файлов .txt, код возвращает ошибку «Отказано в доступе».Я понял, что shutil.copy не позволяет копировать папки.

Цель - скопировать только текстовые файлы в каждой папке входящих сообщений в другое место.Если имена файлов в разных папках входящих сообщений совпадают, я должен сохранить оба имени файлов.Как мы можем улучшить код в этом случае?Обратите внимание, что кроме .txt все остальные являются только папками.

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Только что вспомнил, что однажды я написал несколько файлов, чтобы решить эту проблему раньше. Вы можете найти исходный код здесь, на моем 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)

Схема переименования может быть не совсем той, которую вы хотите, но она, по крайней мере, не переопределит ваши файлы. Я считаю, что это должно решить все ваши проблемы.

0 голосов
/ 13 сентября 2018

Вот, пожалуйста:

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

Если вам нужно скопировать все файлы, а не только текстовые файлы, просто измените условие f.endswith('.txt') на os.path.isfile(f) при фильтрации файлов.

0 голосов
/ 12 сентября 2018

Одним из простых решений является фильтрация для любого i, который не имеет расширения .txt, с помощью метода endswith().

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). Я считаю, что это то, что вы ищете.

...