2010-03-21 41 views
45

Tôi muốn nhanh chóng tìm thấy tổng kích thước của bất kỳ thư mục nào bằng cách sử dụng python.rất nhanh chóng nhận được tổng kích thước của thư mục

import os 
from os.path import join, getsize, isfile, isdir, splitext 
def GetFolderSize(path): 
    TotalSize = 0 
    for item in os.walk(path): 
     for file in item[2]: 
      try: 
       TotalSize = TotalSize + getsize(join(item[0], file)) 
      except: 
       print("error with file: " + join(item[0], file)) 
    return TotalSize 
print(float(GetFolderSize("C:\\")) /1024 /1024 /1024) 

Đó là tập lệnh đơn giản tôi đã viết để nhận được tổng kích thước của thư mục, mất khoảng 60 giây (+ -5 giây). Bằng cách sử dụng đa xử lý tôi đã nhận nó xuống đến 23 giây trên một máy lõi tứ.

Sử dụng trình khám phá tệp Windows chỉ mất ~ 3 giây (Nhấp chuột phải-> thuộc tính để xem cho chính bạn). Vì vậy, có một cách nhanh hơn để tìm tổng kích thước của một thư mục gần với tốc độ mà các cửa sổ có thể làm điều đó?

Windows 7, python 2.6 (Đã tìm kiếm nhưng phần lớn thời gian mọi người sử dụng một phương pháp rất giống với phương pháp của riêng tôi) Cảm ơn bạn trước.

+0

Mã như được trình bày không hợp lệ.Bạn có thể đăng một ví dụ hoàn chỉnh, tối thiểu mà bạn đã thực sự chạy không? – bignose

+0

Xin lỗi, chỉ có chức năng trước đó, phần còn lại của nó được chỉnh sửa. – user202459

+0

liên quan: [Tính toán kích thước thư mục bằng Python?] (Http://stackoverflow.com/questions/1392413/calculating-a-directory-size- sử dụng-python) – jfs

Trả lời

71

Bạn đang ở thế bất lợi.

Windows Explorer gần như chắc chắn sử dụng FindFirstFile/FindNextFile cho cả hai đi qua cấu trúc thư mục thông tin kích thước thu thập (thông qua lpFindFileData) trong một vượt qua, làm những gì bản chất là một cuộc gọi hệ thống duy nhất cho mỗi tập tin.

Thật không may, Python không phải là bạn của bạn trong trường hợp này.Như vậy,

  1. os.walkcuộc gọi đầu tiên os.listdir (mà trong nội bộ gọi FindFirstFile/FindNextFile)
    • bất kỳ cuộc gọi hệ thống thêm làm từ thời điểm này trở đi chỉ có thể làm cho bạn chậm hơn so với Windows Explorer
  2. os.walkrồi gọi isdir cho mỗi tập tin được trả về bởi os.listdir (mà trong nội bộ gọi GetFileAttributesEx - hoặc, trước khi Win2k, một GetFileAttributes + FindFirstFile kết hợp) để redetermine liệu để recurse hay không
  3. os.walkos.listdir sẽ thực hiện thêm phân bổ bộ nhớ, chuỗi và mảng hoạt động vv để điền giá trị trả về của họ
  4. bạn sau đó gọi getsize cho mỗi tập tin được trả về bởi os.walk (mà lại cuộc gọi GetFileAttributesEx)

Đó là nhiều hơn 3 lần cuộc gọi hệ thống trên mỗi tệp so với Windows Explorer, cộng với phân bổ bộ nhớ và thao tác trên không.

Bạn có thể sử dụng giải pháp Anurag, hoặc cố gắng gọi FindFirstFile/FindNextFile trực tiếp và đệ quy (mà phải được so sánh với hiệu suất của một cygwin hoặc khác win32 portdu -s some_directory.)

Tham khảo os.py cho việc thực hiện các os.walk , posixmodule.c thi hành listdirwin32_stat (gọi bởi cả isdirgetsize.)

Lưu ý rằng Python của os.walk là tối ưu trên tất cả các nền tảng (Windows và * nices), tối đa và bao gồm Python3.1. Trên cả Windows và * nices os.walk có thể đạt được traversal trong một lần mà không gọi isdir vì cả hai FindFirst/FindNext (Windows) và opendir/readdir (* nix) đã trở lại loại tập tin thông qua lpFindFileData->dwFileAttributes (Windows) và dirent::d_type (* nix).

lẽ counterintuitively, trên hầu hết các cấu hình hiện đại (ví dụ Win7 và NTFS, và thậm chí một số triển khai SMB) GetFileAttributesExhai lần chậm như FindFirstFile của một tập tin duy nhất (thậm chí có thể chậm hơn so với iterating trên một thư mục với FindNextFile.)

Cập nhật: Python 3.5 bao gồm hàm PEP 471os.scandir() mới giải quyết được vấn đề này bằng cách trả lại thuộc tính tệp cùng với tên tệp. Chức năng mới này được sử dụng để tăng tốc độ tích hợp sẵn trong os.walk() (trên cả Windows và Linux). Bạn có thể sử dụng scandir module on PyPI để nhận hành vi này cho các phiên bản Python cũ hơn, bao gồm 2.x.

+1

PEP được đề cập trang chứa một ví dụ cho chính xác mục đích này: https://www.python.org/dev/peps/pep-0471/#examples – Hossein

20

Nếu bạn muốn tốc độ tương tự như trình thám hiểm, tại sao không sử dụng kịch bản cửa sổ để truy cập cùng chức năng bằng pythoncom, ví dụ:

import win32com.client as com 

folderPath = r"D:\Software\Downloads" 
fso = com.Dispatch("Scripting.FileSystemObject") 
folder = fso.GetFolder(folderPath) 
MB = 1024 * 1024.0 
print("%.2f MB" % (folder.Size/MB)) 

Nó sẽ hoạt động giống như trình thám hiểm, bạn có thể đọc thêm về Thời gian chạy tập lệnh tại http://msdn.microsoft.com/en-us/library/bstcxhf7(VS.85).aspx.

+1

Điều đó hoạt động tuyệt vời, thực sự tuyệt vời. Nhưng hầu hết thời gian. Trong một thư mục ('C: \ Downloads') với kích thước 37GB và 7 000 tệp, phương thức của bạn nhận được là kết quả gần như ngay lập tức. Cách os.walk() nhận được kết quả sau một vài giây (3 giây) Nhưng tôi có một số vấn đề về các thư mục khác như C: \ Windows, C: \ users vv. – user202459

+1

@freakazo, C: \ Windows đã làm việc trên máy của tôi, bạn gặp phải lỗi gì? –

+1

Traceback (cuộc gọi gần đây nhất): Tệp "Test.py", dòng 7, trong in "% .2f MB"% (thư mục.Size/MB) Tệp "C: \ python26_32 \ lib \ site- gói \ win32com \ client \ dynamic.py ", dòng 501, trong __getattr__ ret = self._oleobj_.Invoke (retEntry.dispid, 0, invoke_type, 1) pywintypes.com_error: (-2147352567, 'Ngoại lệ xảy ra'. , (0, None, None, None, 0, -2146828218), None) Nhấn phím bất kỳ để tiếp tục. . . ### Một vài thử nghiệm khác cho thấy rằng đó là folder.size đang gây ra vấn đề. folder.name cho ví dụ hoạt động trên thư mục C: \ Windows – user202459

5

Tôi đã so sánh hiệu suất của mã Python với cây thư mục 15k chứa các tệp 190k và so sánh với lệnh du(1) có thể diễn ra nhanh như hệ điều hành. Mã Python mất 3,3 giây so với du mất 0,8 giây. Đây là trên Linux.

Tôi không chắc chắn có nhiều điều để ép ra khỏi mã Python. Cũng lưu ý rằng lần chạy đầu tiên của du mất 45 giây mà rõ ràng là trước khi các nút i có liên quan nằm trong bộ nhớ cache khối; do đó hiệu suất này phụ thuộc nhiều vào hệ thống quản lý cửa hàng của mình tốt đến mức nào. Nó sẽ không ngạc nhiên nếu một trong hai hoặc cả hai:

  1. os.path.getsize là tiểu tối ưu trên Windows
  2. của Windows lưu trữ nội dung thư mục kích thước một lần tính
+2

Dường như nó thực sự chậm hơn trên các cửa sổ, trên các cửa sổ có cây thư mục 23K và các tệp 175K mất khoảng 60 giây. Sử dụng các cửa sổ du tương đương mất 6 giây để hoàn thành. Vì vậy, nó trông giống như Python là 10x chậm hơn trên cửa sổ hơn du và 4 lần chậm hơn trên Linux. Vì vậy, yip có vẻ như là 1. os.path.getsize/os.walk thực sự là tối ưu trên các cửa sổ 2. Windows dường như lưu trữ kích thước nội dung thư mục 3. Windows vẫn chậm hơn linux – user202459

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