2010-02-01 9 views
6

Ich habe einen Ordner mit 100k Textdateien. Ich möchte Dateien mit mehr als 20 Zeilen in einen anderen Ordner legen. Wie mache ich das in Python? Ich habe os.listdir benutzt, aber natürlich ist nicht genug Speicher vorhanden, um die Dateinamen in den Speicher zu laden. Gibt es eine Möglichkeit, um vielleicht 100 Dateinamen gleichzeitig zu erhalten?Filterdateien in einem sehr großen Ordner

Hier ist mein Code:

import os 
import shutil 

dir = '/somedir/' 

def file_len(fname): 
    f = open(fname,'r') 
    for i, l in enumerate(f): 
     pass 
    f.close() 
    return i + 1 

filenames = os.listdir(dir+'labels/') 

i = 0 
for filename in filenames: 
    flen = file_len(dir+'labels/'+filename) 
    print flen 
    if flen > 15: 
     i = i+1 
     shutil.copyfile(dir+'originals/'+filename[:-5], dir+'filteredOrigs/'+filename[:-5]) 
print i 

und Ausgang:

Traceback (most recent call last): 
    File "filterimage.py", line 13, in <module> 
    filenames = os.listdir(dir+'labels/') 
OSError: [Errno 12] Cannot allocate memory: '/somedir/' 

Hier ist das modifizierte Skript:

import os 
import shutil 
import glob 

topdir = '/somedir' 

def filelen(fname, many): 
    f = open(fname,'r') 
    for i, l in enumerate(f): 
     if i > many: 
      f.close() 
      return True 
    f.close() 
    return False 

path = os.path.join(topdir, 'labels', '*') 
i=0 
for filename in glob.iglob(path): 
    print filename 
    if filelen(filename,5): 
     i += 1 
print i 

es funktioniert auf einem Ordner mit weniger Dateien, aber mit dem größeren Ordner, alles, was es druckt ist "0" ... Funktioniert auf Linux-Server, druckt 0 auf Mac ... oh well ...

+3

"Es ist nicht genug Speicher vorhanden, um die Dateinamen in den Speicher zu laden" Wirklich? 100K Dateinamen sind nicht wirklich viel Speicher. Welchen Fehler bekommst du? Können Sie den Codeschnipsel posten? –

+1

Warum ist Speicher ein Problem? 100k Dateien mit Namen von zB 10 Zeichen sind 10^7 Bytes = 10 Megabyte, nicht wirklich groß. –

+0

Ich stimme zu, dass ein OOM seltsam ist. Was passiert, wenn Sie 'filenames = os.listdir ('/ somedir/labels /')' an der REPL eingeben? –

Antwort

4

Sie könnten mit glob.iglob versuchen, die einen Iterator zurückgibt:

topdir = os.path.join('/somedir', 'labels', '*') 
for filename in glob.iglob(topdir): 
    if filelen(filename) > 15: 
      #do stuff 

bitte auch nicht dir für einen Variablennamen verwenden Sie: Sie können die Einbau-Shadowing sind. Eine weitere wichtige Verbesserung, die Sie einführen können, ist Ihre filelen Funktion. Wenn Sie es durch Folgendes ersetzen, sparen Sie viel Zeit. Vertrauen Sie mir, what you have now is the slowest alternative:

def many_line(fname, many=15): 
    for i, line in enumerate(open(fname)): 
     if i > many: 
      return True 
    return False 
+0

Hat jemand die 'many_line'-Funktion gelesen, bevor er den Upvote-Button gedrückt hat ??? –

+0

@John: Kann hier jemand Tippfehler von der wirklichen Frage unterscheiden? – SilentGhost

+0

+1 Fettester Tippfehler des Jahres Preis –

0
import os,shutil 
os.chdir("/mydir/") 
numlines=20 
destination = os.path.join("/destination","dir1") 
for file in os.listdir("."): 
    if os.path.isfile(file): 
     flag=0 
     for n,line in enumerate(open(file)): 
      if n > numlines: 
       flag=1 
       break 
     if flag: 
      try: 
       shutil.move(file,destination) 
      except Exception,e: print e 
      else: 
       print "%s moved to %s" %(file,destination) 
+0

Das ist die grundlegende Aufgabe, die cseric zu erfüllen versucht, aber es ist keine Antwort auf seine Frage. – jcdyer

+0

ja ist es. Er fragte, wie man mit Python Dateien mit mehr als 20 Zeilen in einen anderen Ordner schreiben könne. – ghostdog74

+2

Nein, er fragte, wie man das für ein Verzeichnis mit 100.000 Dateien tun könne, und notiere, dass das Aufrufen von os.listdir ("."), Wie du es tust, bedeutet, dass er nicht mehr genügend Speicher hat. –

2

Ein paar Gedanken. Zuerst könnten Sie das Modul glob verwenden, um kleinere Gruppen von Dateien zu erhalten. Zweitens wird das Sortieren nach Zeilenanzahl sehr zeitaufwendig sein, da Sie jede Datei öffnen und Zeilen zählen müssen. Wenn Sie nach Byteanzahl partitionieren können, können Sie das Öffnen der Dateien vermeiden, indem Sie das Modul stat verwenden. Wenn es wichtig ist, dass die Aufteilung nach 20 Zeilen erfolgt, können Sie zumindest große Dateimengen ausschneiden, indem Sie eine Mindestanzahl an Zeichen ermitteln, die eine Datei mit 20 Zeilen Ihres Typs haben soll, und keine Datei kleiner als diese öffnen.

0

wie etwa ein Shell-Skript?

for f in `ls`; 
loop 
if `wc -l f`>20; then 
    mv f newfolder 
fi 
end loop 

ppl bitte korrigieren, wenn ich falsch bin in keiner Weise

+1

Verwenden Sie nicht ls mit for-Schleife so. Es bricht Dateien mit Leerzeichen .use Shell-Erweiterung. – ghostdog74

0

Die derzeit akzeptierte Antwort einfach nur nicht funktioniert: Sie konnte eine Datei auf einmal auswählen. Diese Funktion:

def many_line(fname, many=15): 
    for i, line in enumerate(line): 
     if i > many: 
      return True 
    return False 

hat zwei Probleme: Erstens ist die fname arg nicht verwendet wird, und die Datei nicht geöffnet wird. Zweitens wird der Aufruf an enumerate(line) fehlschlagen, da line nicht definiert ist.

Ändern enumerate(line) zu enumerate(open(fname)) wird es beheben.

Verwandte Themen