ディスクの空き容量を調べる、 Linux, Windows 両対応
seko さん、 bonlife さんに続き、ディスクの空き容量を調べる Python コードの作成に挑戦しました。動作確認は Windows と Debian にて行っています。
disk_free(path) 関数は Unix の df コマンドのように path を含むファイルシステムの総容量、使用済み量、(現ユーザーの)使用可能量を返します。
2009/5/28 修正。 disk_free 関数の docstring 誤記。空き容量を使用量に。
# coding: utf-8 import os __all__ = [ 'disk_free', 'get_avail_size', 'get_total_size', 'get_used_size'] if os.name == 'nt': from ctypes import windll, WINFUNCTYPE, POINTER from ctypes import GetLastError, FormatError from ctypes import c_ulonglong from ctypes.wintypes import BOOL, LPCSTR, LPCWSTR ULARGE_INTEGER = c_ulonglong PULARGE_INTEGER = POINTER(ULARGE_INTEGER) if True: # UNICODE ビルド環境 LPCTSTR = LPCWSTR _GetDiskFreeSpaceEx = 'GetDiskFreeSpaceExW' else: # ASCII ビルド環境、 os.name=='nt' では存在しない? LPCTSTR = LPCSTR _GetDiskFreeSpaceEx = 'GetDiskFreeSpaceExA' def _GetDiskFreeSpaceExErrcheck(result, func, args): if result == 0: error_code = GetLastError() error_message = FormatError(error_code) raise WindowsError( error_code, error_message) return args GetDiskFreeSpaceEx = WINFUNCTYPE(BOOL, LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)( (_GetDiskFreeSpaceEx, windll.kernel32), ( (1, 'lpDirectoryName', None), (2, 'lpFreeBytesAvailable'), (2, 'lpTotalNumberOfBytes'), (2, 'lpTotalNumberOfFreeBytes'))) GetDiskFreeSpaceEx.errcheck = _GetDiskFreeSpaceExErrcheck def disk_free(path): u""" path の総容量、使用量、(現ユーザーの)使用可能容量を返す """ avail, total, free = GetDiskFreeSpaceEx(path) used = total - free return total, used, avail else: def disk_free(path): u""" path の総容量、使用量、(現ユーザーの)使用可能容量を返す """ s = os.statvfs(path) avail = s.f_bsize * s.f_bavail total = s.f_bsize * s.f_blocks free = s.f_bsize * s.f_bfree used = total - free return total, used, avail def get_total_size(path): return disk_free(path)[0] def get_used_size(path): return disk_free(path)[1] def get_avail_size(path): return disk_free(path)[2] def _test(): print disk_free(r'.') if __name__ == '__main__': _test()
Windows 版解説
Windows では GetDiskFreeSpaceEx を ctypes 経由で使用しています。
この API はポインタを渡して、値を書いてもらうことで結果を得るタイプのものです。この処理を ctypes で行うための素直な方法は、受け取り元となる c_longlong 型を作り、これを参照する簡易ポインタを byref 関数を使用して作り、 この簡易ポインタを GetDiskFreeSpaceEx に渡す、です。
しかし、この一連の処理は ctypes に任せることが可能です。使用する側は楽になる反面、 GetDiskFreeSpaceEx 外部関数を定義する側の手間は増えてしまいますが。
まずは WINFUNCTYPE を使用してプロトタイプを作ります。 WINFUNCTYPE に与えるべき値は戻り値の型と引数の型を並べたものです。
そうしてできたプロトタイプを実行し、外部関数を作ります。第 1 引数は関数名と共有ライブラリのタプルです。第 2 引数は外部関数の引数の扱いを表すタプルのタプルです。
通常、 ((1, 'argName1', 'default_value1'), (1, 'argName2', 'default_value2)) のように「1 と引数名とデフォルト値」にします。引数名とデフォルト値は省略可能です。
ポインタを渡して値を受け取るだけの引数には 1 ではなく 2 を指定します。つまり「2 と引数名とデフォルト値」です。たとえば (2, 'lpFreeBytesAvailable') とします。 2 の引数をもつ外部関数の戻り値は、本来の戻り値ではなく、 2 の引数に書かれるべき値のタプルになります。本来の戻り値は得られなくなるので、 errcheck 関数を駆使して例外処理をおこなうべきです。
詳しくは http://www.python.jp/doc/release/lib/ctypes-function-prototypes.html を参照してください。
なお、pywin32 が使える環境ならば 9-39 行目を次の 1 行に取り替えることができるのは bonlife さんの記事どおりです。 ctypes も不要です。
from win32api import GetDiskFreeSpaceEx