2010-02-01 48 views
6

Tôi có một thư mục chứa 100k tệp văn bản. Tôi muốn đặt các tập tin với hơn 20 dòng trong một thư mục khác. Làm thế nào để làm điều này trong python? Tôi đã sử dụng os.listdir, nhưng tất nhiên, không đủ bộ nhớ để tải các tên tập tin vào bộ nhớ. Có cách nào để lấy 100 tên tập tin cùng một lúc không?Lọc tệp trong một thư mục rất lớn

Dưới đây là mã của tôi:

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 

Và Output:

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

Dưới đây là kịch bản biến đổi:

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 

nó hoạt động trên một thư mục với các file ít hơn, nhưng với sự lớn thư mục, tất cả nó in là "0" ... Hoạt động trên máy chủ Linux, in 0 trên máy Mac ... ồ ...

+3

"không đủ bộ nhớ để tải các tên tệp vào bộ nhớ" Thật không? 100K tên tập tin không thực sự là tất cả những gì nhiều bộ nhớ. lỗi gì bạn nhận được? Bạn có thể đăng đoạn mã không? –

+1

Tại sao bộ nhớ là vấn đề? 100k tệp có tên, giả sử 10 ký tự, là 10^7 byte = 10 megabyte, không quá lớn. –

+0

Tôi đồng ý rằng OOM là lạ. Điều gì xảy ra nếu bạn nhập 'filenames = os.listdir ('/ somedir/labels /')' tại REPL? –

Trả lời

4

bạn có thể thử sử dụng glob.iglob mà trả về một iterator:

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

Ngoài ra, xin vui lòng không sử dụng dir cho một tên biến: bạn đang shadowing built-in.

Một cải tiến quan trọng khác mà bạn có thể giới thiệu là chức năng filelen của bạn. Nếu bạn thay thế nó bằng những điều sau đây, bạn sẽ tiết kiệm rất nhiều thời gian. Hãy tin tôi, 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

Có ai đọc chức năng 'many_line' trước khi nhấn nút upvote không ??? –

+0

@John: bất kỳ ai ở đây có thể phân biệt lỗi chính tả từ vấn đề thực sự không? – SilentGhost

+0

+1 typo béo nhất của giải thưởng năm –

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

Đó là nhiệm vụ cơ bản mà cseric đang cố gắng thực hiện, nhưng nó không phải là câu trả lời cho câu hỏi của anh ta. – jcdyer

+0

vâng. Anh ta hỏi làm thế nào để đưa các tập tin với hơn 20 dòng vào một thư mục khác bằng cách sử dụng Python. – ghostdog74

+2

Không, anh ta hỏi làm thế nào để làm điều đó cho một thư mục có 100.000 tập tin, lưu ý rằng gọi os.listdir ("."), Như bạn làm, có nghĩa là ông hết bộ nhớ. –

2

Một vài suy nghĩ. Trước tiên, bạn có thể sử dụng mô-đun glob để nhận các nhóm tệp nhỏ hơn. Thứ hai, sắp xếp theo số dòng sẽ tốn rất nhiều thời gian, vì bạn phải mở mọi tệp và đếm các dòng. Nếu bạn có thể phân vùng theo số byte, bạn có thể tránh mở tệp bằng cách sử dụng mô-đun stat. Nếu điều quan trọng là sự phân chia xảy ra ở 20 dòng, bạn ít nhất có thể cắt ra các tệp lớn bằng cách tìm ra số ký tự tối thiểu mà một tệp 20 dòng thuộc loại của bạn sẽ có và không mở bất kỳ tệp nào nhỏ hơn.

0

cách sử dụng tập lệnh shell? bạn có thể chọn một tập tin tại một thời điểm:

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

ppl hãy sửa lại nếu tôi đã sai lầm trong bất kỳ cách nào

+1

không sử dụng ls với vòng lặp như thế. Nó phá vỡ trên các tập tin có dấu cách. – ghostdog74

0

Câu trả lời chấp nhận hiện nay chỉ đơn giản không hoạt động. Chức năng này:

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

có hai vấn đề: Thứ nhất, fname arg không được sử dụng và tệp không được mở. Thứ hai, cuộc gọi đến enumerate(line) sẽ không thành công vì line không được xác định.

Thay đổi enumerate(line) thành enumerate(open(fname)) sẽ khắc phục.

Các vấn đề liên quan