2013-11-27 1 views
6

Я пытаюсь написать программу, которая принимает аргумент командной строки, просматривает дерево каталогов, предоставленное аргументом, и создает список всех файлов в каталоге, а затем сортирует по длине файлов.Получить файлы из Аргумента Directory, Сортировка по размеру

Я не так много сценариев-парень, - но это то, что у меня есть, и это не работает:

import sys 
import os 
from os.path import getsize 

file_list = [] 

#Get dirpath 
dirpath = os.path.abspath(sys.argv[0]) 
if os.path.isdir(dirpath): 
    #Get all entries in the directory 
    for root, dirs, files in os.walk(dirpath): 
     for name in files: 
      file_list.append(name) 
     file_list = sorted(file_list, key=getsize) 
     for item in file_list: 
      sys.stdout.write(str(file) + '\n') 

else: 
    print "not found" 

Может кто-нибудь мне точку в правильном направлении?

+0

Я предлагаю прочитать справку для функции [ 'о s.walk'] (http://docs.python.org/2/library/os.html#os.walk). Кажется, это правильный выбор для работы с деревьями каталогов. Если вы посмотрите на пример этой функции, вы увидите, что вы на хорошем пути ... – koffein

+0

Я думаю, что ваша предыдущая строка не нужна. на самом деле эта строка вызывает ошибку ... – koffein

+0

@koffein Я обновил свой код, но он все еще дает мне ошибку. –

ответ

6

Надеюсь, эта функция поможет вам (я использую Python 2.7):

import os  

def get_files_by_file_size(dirname, reverse=False): 
    """ Return list of file paths in directory sorted by file size """ 

    # Get list of files 
    filepaths = [] 
    for basename in os.listdir(dirname): 
     filename = os.path.join(dirname, basename) 
     if os.path.isfile(filename): 
      filepaths.append(filename) 

    # Re-populate list with filename, size tuples 
    for i in xrange(len(filepaths)): 
     filepaths[i] = (filepaths[i], os.path.getsize(filepaths[i])) 

    # Sort list by file size 
    # If reverse=True sort from largest to smallest 
    # If reverse=False sort from smallest to largest 
    filepaths.sort(key=lambda filename: filename[1], reverse=reverse) 

    # Re-populate list with just filenames 
    for i in xrange(len(filepaths)): 
     filepaths[i] = filepaths[i][0] 

    return filepaths 
+1

Я читал это несколько раз, и я вижу, что это работает, но я также заметил, что вы не обнаружили все мелочи, которые делают ваш код Python более красивым и читабельны. Надеюсь, вы оцените некоторые рекомендации: Всякий раз, когда вы думаете, что вам нужно написать 'for i в диапазоне (len (some_list))', используйте ['перечисление'] (http://docs.python.org/2/library/functions .html # enumerate). Если вы хотите повторно заполнить список, оставьте свой «массив мышления», попробуйте использовать что-то вроде этого: 'lst = [do_something (entry) для записи в lst]' ... – koffein

+2

Но если вы создаете список, вы хотите повторно заполнить без дальнейшего использования, подумайте об использовании генераторов. Таким образом, вам не придется перебирать список снова и снова ...экономит память, время ... Если вы устали читать это, смотрите это видео ... после нескольких лет программирования на питоне я смотрел широко открытым ртом! [Преобразование кода в красивый, идиоматический Python] (https://www.youtube.com/watch?v=OSGv2VnC0go) – koffein

+0

'dirname' - зарезервированное имя для функции в' os.path', вы не должны ее использовать как имя переменной в вашем скрипте. Функция отлично работает! – Gabriel

0

Вы извлекаете команду, а не первый аргумент argv[0]; использовать argv[1] для этого:

dirpath = sys.argv[1] # argv[0] contains the command itself. 

По соображениям производительности я предлагаю вам упреждающие размеры файлов вместо того, чтобы просить ОСА о размере одного и тот же файл несколько раз во время сортировки (как это было предложено Кофеин, os.walk является способом перейти):

files_list = [] 
for path, dirs, files in os.walk(dirpath)): 
    files_list.extend([(os.path.join(path, file), getsize(os.path.join(path, file))) for file in files]) 

Предполагая, что вы не нуждаетесь в несортированный список, мы будем использовать сортировку на месте() метод:

files_list.sort(key=operator.itemgetter(1)) 
+0

'files'-list - это список имен файлов, не так ли? Я думаю, вам нужно присоединиться к 'file'-names с' path' – koffein

5

Это подход с использованием генераторов. Должно быть быстрее для большого количества файлов ...

Это начало обоих примеров:

import os, operator, sys 
dirpath = os.path.abspath(sys.argv[0]) 
# make a generator for all file paths within dirpath 
all_files = (os.path.join(basedir, filename) for basedir, dirs, files in os.walk(dirpath) for filename in files ) 

Если вы просто хотите получить список файлов без размера, вы можете использовать это:

sorted_files = sorted(all_files, key = os.path.getsize) 

Но если вы хотите, чтобы файлы и пути в списке, вы можете использовать это:

# make a generator for tuples of file path and size: ('/Path/to/the.file', 1024) 
files_and_sizes = ((path, os.path.getsize(path)) for path in all_files) 
sorted_files_with_size = sorted(files_and_sizes, key = operator.itemgetter(1)) 
+0

Используйте 'sorted_files_with_size.reverse()', чтобы увидеть самые большие файлы в первую очередь. Это довольно быстро и полезно быстро понять, какие файлы занимают место. –

Смежные вопросы