У меня есть папка с 100k текстовыми файлами. Я хочу поместить файлы с более чем 20 строками в другой папке. Как я делаю это в Python? Я использовал os.listdir, но конечно, нет достаточной памяти для того, чтобы даже загрузить имена файлов в память. Существует ли способ получить, возможно, 100 имен файлов за один раз?
Вот мой код:
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
И вывод:
Traceback (most recent call last):
File "filterimage.py", line 13, in <module>
filenames = os.listdir(dir+'labels/')
OSError: [Errno 12] Cannot allocate memory: '/somedir/'
Вот измененный сценарий:
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
это работает над папкой с меньшим количеством файлов, но с большей папкой, все, что это печатает, "0"... Работы над сервером Linux, печать 0 на Mac..., о, хорошо...
Вы можете попробовать использовать GLOCH.GLOB
, который возвращает итератор:
topdir = os.path.join('/somedir', 'labels', '*')
for filename in glob.iglob(topdir):
if filelen(filename) > 15:
#do stuff
также, пожалуйста, не используйте DIR
для имени переменной: вы слежены в.
Еще одним серьезным улучшением, которое вы можете представить, является вашим FileLen
функции. Если вы замените его следующим, вы сэкономите много времени. Поверьте мне, То, что у вас сейчас самая медленная альтернатива :
def many_line(fname, many=15):
for i, line in enumerate(open(fname)):
if i > many:
return True
return False
как насчет использования скрипта оболочки? Вы можете выбрать один файл за раз:
for f in `ls`;
loop
if `wc -l f`>20; then
mv f newfolder
fi
end loop
ppl пожалуйста, исправьте, если я ошибаюсь в любом случае
.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)
В настоящее время принятый ответ просто просто не работает. Эта функция:
def many_line(fname, many=15):
for i, line in enumerate(line):
if i > many:
return True
return False
имеет две проблемы: во-первых, FNAME
ARG не используется, и файл не открывается. Во-вторых, призыв к перечислите (строку)
, поскольку линия
не определена.
Изменение перечисление
.
Перечисление (Open (Fname))
исправит его.
Пара мыслей. Во-первых, вы можете использовать модуль glob
для получения небольших групп файлов. Во-вторых, сортировка по количеству строк займет очень много времени, так как вам придется открывать каждый файл и подсчитывать строки. Если вы можете разбивать файлы по количеству байтов, вы можете избежать открытия файлов с помощью модуля stat
. Если критически важно, чтобы разделение происходило на 20 строках, вы можете, по крайней мере, вырезать большие участки файлов, вычислив минимальное количество символов, которое будет иметь 20-строчный файл вашего типа, и не открывать файлы меньшего размера.