2013-07-09 10 views
2

Я хочу переместить файлы из сложной структуры каталога в одно место. Например у меня есть эта глубокая иерархия:Сложная структура каталогов в Python

foo/ 
    foo2/ 
     1.jpg 
    2.jpg 
    ... 

Я хочу, чтобы это было:

1.jpg 
2.jpg 
... 

Мое текущее решение:

def move(destination): 
    for_removal = os.path.join(destination, '\\') 
    is_in_parent = lambda x: x.find(for_removal) > -1 
    with directory(destination): 
     files_to_move = filter(is_in_parent, 
           glob_recursive(path='.')) 
    for file in files_to_move: 
     shutil.move(file, destination) 

Определения: directory и glob_recursive. Обратите внимание, что мой код только перемещает файлы в их общий родительский каталог, а не в произвольное место назначения.

Как перенести все файлы из сложной иерархии в одно место лаконично и элегантно?

ответ

1

Выполнить рекурсивно через каталог, перемещать файлы и запускать move для каталогов:

import shutil 

def move(destination, depth=None): 
    if not depth: 
     depth = [] 
    for file_or_dir in os.listdir(os.path.join([destination] + depth, "\\")): 
     if os.path.isfile(file_or_dir): 
      shutil.move(file_or_dir, destination) 
     else: 
      move(destination, os.path.join(depth + [file_or_dir], "\\")) 
2

это будет делать, он также переименовывает файлы, если они сталкиваются (я закомментирована фактическим ходом и заменена копией):

import os 
import sys 
import string 
import shutil 

#Generate the file paths to traverse, or a single path if a file name was given 
def getfiles(path): 
    if os.path.isdir(path): 
     for root, dirs, files in os.walk(path): 
      for name in files: 
       yield os.path.join(root, name) 
    else: 
     yield path 

destination = "./newdir/" 
fromdir = "./test/" 
for f in getfiles(fromdir): 
    filename = string.split(f, '/')[-1] 
    if os.path.isfile(destination+filename): 
     filename = f.replace(fromdir,"",1).replace("/","_") 
    #os.rename(f, destination+filename) 
    shutil.copy(f, destination+filename) 
0
import os.path, shutil 

def move(src, dest): 
    not_in_dest = lambda x: os.path.samefile(x, dest) 
    files_to_move = filter(not_in_dest, 
          glob_recursive(path=src)) 

    for f in files_to_move: 
     shutil.move(f, dest) 

Source для glob_recursive. Не меняет имя файла, если он сталкивается.

samefile - безопасный способ сравнения путей. Но он не работает в Windows, поэтому проверьте How to emulate os.path.samefile behaviour on Windows and Python 2.7?.

1

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

import os 
import itertools 
import shutil 


def move(destination): 
    all_files = [] 
    for root, _dirs, files in itertools.islice(os.walk(destination), 1, None): 
     for filename in files: 
      all_files.append(os.path.join(root, filename)) 
    for filename in all_files: 
     shutil.move(filename, destination) 

Объяснение: os.walk ходит рекурсивно назначения в «сверху вниз» способом. целые имена файлов создаются с вызовом os.path.join (root, filename). Теперь, чтобы предотвратить сканирование файлов в верхней части адресата, нам просто нужно игнорировать первый элемент итерации os.walk. Для этого я использую islice (iterator, 1, None). Другим более явным способом было бы сделать это:

def move(destination): 
    all_files = [] 
    first_loop_pass = True 
    for root, _dirs, files in os.walk(destination): 
     if first_loop_pass: 
      first_loop_pass = False 
      continue 
     for filename in files: 
      all_files.append(os.path.join(root, filename)) 
    for filename in all_files: 
     shutil.move(filename, destination) 
+0

Вы не обрабатываете случай, когда имя файла, которое вы перемещаете, совпадает с именем файла в каталоге назначения. Например, что, если исходные sub dirs содержат только файлы с именем hello.txt? move() вызовет ошибку. – 7stud

+0

Это решение также оставит пустые вспомогательные каталоги. Чтобы решить: храните _dirs рядом с тем, где вы устанавливаете first_loop_pass в False, а затем в конце после того, как вы делаете файл, перемещается только по кругу и вызывает shutil.rmtree() – Ben