2017-05-08 47 views
18

Mam kilka plików w kilku folderach tak:Jak przenosić i zmieniać nazwy dokumentów umieszczonych w kilku zagnieżdżonych folderach w nowym pojedynczym folderze z pythonem?

dir 
├── 0 
│   ├── 103425.xml 
│   ├── 105340.xml 
│   ├── 109454.xml 
│ 
│── 1247 
│   └── doc.xml 
├── 14568 
│   └── doc.xml 
├── 1659 
│   └── doc.xml 
├── 10450 
│   └── doc.xml 
├── 10351 
│   └── doc.xml 

Jak można wyodrębnić wszystkie dokumenty w jednym folderze dołączenie nazwy folderu dla każdego przeniósł dokument:

new_dir 
├── 0_103425.xml 
├── 0_105340.xml 
├── 0_109454.xml 
├── 1247_doc.xml 
├── 14568_doc.xml 
├── 1659_doc.xml 
├── 10450_doc.xml 
├── 10351_doc.xml 

starałem się wyodrębnić im z:

import os 

for path, subdirs, files in os.walk('../dir/'): 
    for name in files: 
     print(os.path.join(path, name)) 

UPDATE

Również próbowałem:

import os, shutil 
from glob import glob 

files = [] 
start_dir = os.getcwd() 
pattern = "*.xml" 

for dir,_,_ in os.walk('../dir/'): 
    files.extend(glob(os.path.join(dir,pattern))) 
for f in files: 
    print(f) 
    shutil.move(f, '../dir/') 

Powyższy dał mi ścieżkę każdego pliku. Jednak nie rozumiem, jak zmienić nazwę i przenieść je:

--------------------------------------------------------------------------- 
Error          Traceback (most recent call last) 
<ipython-input-50-229e4256f1f3> in <module>() 
    10 for f in files: 
    11  print(f) 
---> 12  shutil.move(f, '../dir/') 

/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/shutil.py in move(src, dst, copy_function) 
    540   real_dst = os.path.join(dst, _basename(src)) 
    541   if os.path.exists(real_dst): 
--> 542    raise Error("Destination path '%s' already exists" % real_dst) 
    543  try: 
    544   os.rename(src, real_dst) 

Error: Destination path '../data/230948.xml' already exists 

Powyższy błąd pokazuje, dlaczego chciałbym zmienić nazwę tego folderu.

Odpowiedz

8

Jak to działa dla Ciebie?

import os 
import pathlib 

OLD_DIR = 'files' 
NEW_DIR = 'new_dir' 

p = pathlib.Path(OLD_DIR) 
for f in p.glob('**/*.xml'): 
    new_name = '{}_{}'.format(f.parent.name, f.name) 
    f.rename(os.path.join(NEW_DIR, new_name)) 

Jeśli nie dysponują nowoczesną wersję Pythona (3.5+) można też po prostu użyć glob, OS i shutil:

import os 
import glob 
import shutil 


for f in glob.glob('files/**/*.xml'): 
    new_name = '{}_{}'.format(os.path.basename(os.path.dirname(f)), os.path.basename(f)) 
    shutil.move(f, os.path.join('new_dir', new_name)) 
+0

Wow .... to było łatwiejsze, nie wiedziałem o 'pathlib'. – tumbleweed

+2

Dodałem także, jak można to zrobić za pomocą shutil, os i glob. –

+0

Jestem w python3 faktycznie! – tumbleweed

7

to najłatwiej zrobić z Python 3 nowego pathlib moduł do operacji na ścieżkach, a następnie shutil.move do przenoszenia plików do ich właściwych miejsc. W przeciwieństwie do os.rename, shutil.move będzie działać tak, jak polecenie mv i zachowywać się poprawnie nawet w przypadku ruchów systemu plików krzyżowych.

Kod ten będzie działać zagnieżdżonych ścieżek do dowolnego poziomu - każdy / lub \ w ścieżkach zostanie zastąpiony _ w docelowym pliku, więc dir/foo/bar/baz/xyzzy.xml zostanie przeniesiony do new_dir/foo_bar_baz_xyzzy.xml.

from pathlib import Path 
from shutil import move 

src = Path('dir') 
dst = Path('new_dir') 

# create the target directory if it doesn't exist 
if not dst.is_dir(): 
    dst.mkdir() 

# go through each file 
for i in src.glob('**/*'): 
    # skip directories and alike 
    if not i.is_file(): 
     continue 

    # calculate path relative to `src`, 
    # this will make dir/foo/bar into foo/bar 
    p = i.relative_to(src) 

    # replace path separators with underscore, so foo/bar becomes foo_bar 
    target_file_name = str(p).replace('/', '_').replace('\\', '_') 

    # then do rename/move. shutil.move will always do the right thing 
    # note that it *doesn't* accept Path objects in Python 3.5, so we 
    # use str(...) here. `dst` is a path object, and `target_file_name 
    # is the name of the file to be placed there; we can use the/operator 
    # instead of os.path.join. 
    move(str(i), str(dst/target_file_name)) 
+0

Dzięki antti, świetna odpowiedź! – tumbleweed