2013-07-09 27 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) 

定義:directoryglob_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) 

Sourceglob_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

你不處理你正在移動的文件名與目標目錄中的文件名相同的情況。例如,如果源子目錄僅包含名爲hello.txt的文件呢? move()會拋出一個錯誤。 – 7stud

+0

這個解決方案也會留下空的子目錄。爲了解決:商店_dirs你旁邊做文件運行後剛過顯示目錄循環,並呼籲shutil.rmtree,你first_loop_pass設置爲False,然後在最後() – Ben