wake-up-neo.net

Python-rekursiver Ordner gelesen

Ich habe einen C++/Obj-C-Hintergrund und entdecke gerade Python (schreibe es seit ungefähr einer Stunde) ... Ich schreibe ein Skript, um rekursiv den Inhalt von Textdateien in einer Ordnerstruktur zu lesen.

Mein Problem ist, dass der Code, den ich geschrieben habe, nur für einen Ordner funktioniert. Ich kann sehen, warum im Code (siehe #hardcoded path) ich einfach nicht weiß, wie ich mit Python fortfahren kann, da meine Erfahrung damit nur brandneu ist.

Python-Code:

import os
import sys

rootdir = sys.argv[1]

for root, subFolders, files in os.walk(rootdir):

    for folder in subFolders:
        outfileName = rootdir + "/" + folder + "/py-outfile.txt" # hardcoded path
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName

        for file in files:
            filePath = rootdir + '/' + file
            f = open( filePath, 'r' )
            toWrite = f.read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
            f.close()

        folderOut.close()
156
Brock Woolf

Stellen Sie sicher, dass Sie die drei Rückgabewerte von os.walk verstehen:

for root, subdirs, files in os.walk(rootdir):

hat folgende Bedeutung:

  • root: Aktueller Pfad, der "durchlaufen" wird
  • subdirs: Dateien in root vom Typverzeichnis
  • files: Dateien in root (nicht in subdirs) eines anderen Typs als dem Verzeichnis

Und bitte verwenden Sie os.path.join anstatt mit einem Schrägstrich zu verketten! Ihr Problem ist filePath = rootdir + '/' + file - Sie müssen den momentan "gelaufenen" Ordner anstelle des obersten Ordners verketten. Das muss also filePath = os.path.join(root, file) sein. BTW "file" ist eine eingebaute Datei, daher wird sie normalerweise nicht als Variablenname verwendet.

Ein anderes Problem sind Ihre Loops, die zum Beispiel so aussehen sollten:

import os
import sys

walk_dir = sys.argv[1]

print('walk_dir = ' + walk_dir)

# If your current working directory may change during script execution, it's recommended to
# immediately convert program arguments to an absolute path. Then the variable root below will
# be an absolute path as well. Example:
# walk_dir = os.path.abspath(walk_dir)
print('walk_dir (absolute) = ' + os.path.abspath(walk_dir))

for root, subdirs, files in os.walk(walk_dir):
    print('--\nroot = ' + root)
    list_file_path = os.path.join(root, 'my-directory-list.txt')
    print('list_file_path = ' + list_file_path)

    with open(list_file_path, 'wb') as list_file:
        for subdir in subdirs:
            print('\t- subdirectory ' + subdir)

        for filename in files:
            file_path = os.path.join(root, filename)

            print('\t- file %s (full path: %s)' % (filename, file_path))

            with open(file_path, 'rb') as f:
                f_content = f.read()
                list_file.write(('The file %s contains:\n' % filename).encode('utf-8'))
                list_file.write(f_content)
                list_file.write(b'\n')

Wenn Sie nicht wussten, ist die with-Anweisung für Dateien eine Abkürzung:

with open('filename', 'rb') as f:
    dosomething()

# is effectively the same as

f = open('filename', 'rb')
try:
    dosomething()
finally:
    f.close()
276
AndiDog

Wenn Sie Python 3.5 oder höher verwenden, können Sie dies in einer Zeile erledigen.

import glob

for filename in glob.iglob(root_dir + '**/*.txt', recursive=True):
     print(filename)

Wie in der Dokumentation erwähnt

Wenn rekursiv wahr ist, stimmt das Muster '** mit allen Dateien und null oder mehr Verzeichnissen und Unterverzeichnissen überein.

Wenn Sie jede Datei wünschen, können Sie verwenden

import glob

for filename in glob.iglob(root_dir + '**/*', recursive=True):
     print(filename)
40
ChillarAnand

Stimmen Sie mit Dave Webb überein: os.walk liefert für jedes Verzeichnis in der Baumstruktur ein Element. Tatsache ist, dass Sie sich nicht um subFolders kümmern müssen.

Code wie dieser sollte funktionieren:

import os
import sys

rootdir = sys.argv[1]

for folder, subs, files in os.walk(rootdir):
    with open(os.path.join(folder, 'python-outfile.txt'), 'w') as dest:
        for filename in files:
            with open(os.path.join(folder, filename), 'r') as src:
                dest.write(src.read())
33
Clément
import glob
import os

root_dir = <root_dir_here>

for filename in glob.iglob(root_dir + '**/**', recursive=True):
    if os.path.isfile(filename):
        with open(filename,'r') as file:
            print(file.read())

**/** wird verwendet, um alle Dateien rekursiv abzurufen, einschließlich directory.

if os.path.isfile(filename) wird verwendet, um zu überprüfen, ob filename variable file oder directory ist. Wenn es sich um eine Datei handelt, können wir diese Datei lesen. Hier drucke ich eine Datei.

4
Neeraj Sonaniya

verwenden Sie os.path.join(), um Ihre Pfade zu konstruieren.

import os
import sys
rootdir = sys.argv[1]
for root, subFolders, files in os.walk(rootdir):
    for folder in subFolders:
        outfileName = os.path.join(root,folder,"py-outfile.txt")
        folderOut = open( outfileName, 'w' )
        print "outfileName is " + outfileName
        for file in files:
            filePath = os.path.join(root,file)
            toWrite = open( filePath).read()
            print "Writing '" + toWrite + "' to" + filePath
            folderOut.write( toWrite )
        folderOut.close()
3
ghostdog74

TL; DR: Dies ist das Äquivalent zu find -type f, um alle Dateien in allen Verzeichnissen darunter und einschließlich des aktuellen zu durchsuchen:

for currentpath, dirs, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

Wie bereits in anderen Antworten erwähnt, ist os.walk() die Antwort, aber es könnte besser erklärt werden. Es ist ganz einfach! Lass uns durch diesen Baum gehen:

docs/
└── doc1.odt
pics/
todo.txt

Mit diesem Code:

for currentpath, folders, files in os.walk('.'):
    print(currentpath)

Das currentpath ist der aktuelle Ordner, in dem es sich befindet. Dies wird Folgendes ausgeben:

.
./docs
./pics

Es wird also dreimal wiederholt, da drei Ordner vorhanden sind: der aktuelle, docs und pics. In jeder Schleife werden die Variablen dirs und files mit allen Ordnern und Dateien gefüllt. Lassen Sie uns ihnen zeigen:

for currentpath, folders, files in os.walk('.'):
    print(currentpath, dirs, files)

Das zeigt uns:

# currentpath  folders           files
.              ['pics', 'docs']  ['todo.txt']
./pics         []                []
./docs         []                ['doc1.odt']

In der ersten Zeile sehen wir also, dass wir uns im Ordner . befinden, dass er zwei Ordner enthält, nämlich pics und docs, und dass es eine Datei gibt, nämlich todo.txt . Sie müssen nichts tun, um in diese Ordner zurückzukehren, da sie, wie Sie sehen, automatisch wiederkehren und Ihnen nur die Dateien in Unterordnern anzeigen. Und alle Unterordner davon (obwohl wir diese im Beispiel nicht haben).

Wenn Sie nur alle Dateien durchlaufen möchten, die find -type f entsprechen, können Sie dies tun:

for currentpath, dirs, files in os.walk('.'):
    for file in files:
        print(os.path.join(currentpath, file))

Diese gibt aus:

./todo.txt
./docs/doc1.odt
2
Luc

Versuche dies:

import os
import sys

for root, subdirs, files in os.walk(path):

    for file in os.listdir(root):

        filePath = os.path.join(root, file)

        if os.path.isdir(filePath):
            pass

        else:
            f = open (filePath, 'r')
            # Do Stuff
1
Diego

Ich denke, das Problem ist, dass Sie die Ausgabe von os.walk nicht korrekt verarbeiten.

Ändern Sie zuerst:

filePath = rootdir + '/' + file

zu:

filePath = root + '/' + file

rootdir ist Ihr festes Startverzeichnis; root ist ein von os.walk zurückgegebenes Verzeichnis.

Zweitens müssen Sie Ihre Dateiverarbeitungsschleife nicht einrücken, da es keinen Sinn macht, dies für jedes Unterverzeichnis auszuführen. Sie erhalten root für jedes Unterverzeichnis. Sie müssen die Unterverzeichnisse nicht manuell bearbeiten, es sei denn, Sie möchten etwas mit den Verzeichnissen selbst tun.

0
Dave Webb

Wenn Sie eine flache Liste aller Pfade unter einem bestimmten Verzeichnis möchten (wie find . in der Shell):

   files = [ 
       os.path.join(parent, name)
       for (parent, subdirs, files) in os.walk(YOUR_DIRECTORY)
       for name in files + subdirs
   ]

Lassen Sie + subdirs weg, um nur vollständige Pfade zu Dateien unter dem Basisverzeichnis aufzunehmen.

0
Scott Smith

os.walk führt standardmäßig rekursive Schritte durch. Ausgehend von root erhält man für jedes Verzeichnis einen 3-Tuple

from os import walk
from os.path import splitext, join

def select_files(root, files):
    """
    simple logic here to filter out interesting files
    .py files in this example
    """

    selected_files = []

    for file in files:
        #do concatenation here to get full path 
        full_path = join(root, file)
        ext = splitext(file)[1]

        if ext == ".py":
            selected_files.append(full_path)

    return selected_files

def build_recursive_dir_tree(path):
    """
    path    -    where to begin folder scan
    """
    selected_files = []

    for root, dirs, files in walk(path):
        selected_files += select_files(root, files)

    return selected_files
0
b1r3k