python获取卷或物理驱动器的文件大小

Posted

技术标签:

【中文标题】python获取卷或物理驱动器的文件大小【英文标题】:python get file size of volumes or physical drives 【发布时间】:2017-07-13 11:16:27 【问题描述】:

我正在 Windows 中打开一个卷,如下所示:

 open(filename, 'rb') where filename is r'\\\\.\d:'

问题是我需要获取卷的大小。 我试过了: os.stat, os.path.getsize, seek/tell 没有任何作用,说无效的参数或参数。

我需要一种不使用 win32 特定功能的方法来获得它。

【问题讨论】:

Find size and free space of the filesystem containing a given file的可能重复 在链接的问题中,Windows 只被提及一次,并且那里描述的方法不能普遍应用,因为它需要第三方工具。 【参考方案1】:

对音量进行一些计算

UNIX

使用os.statvfs

import os
statvfs = os.statvfs('/path/to/file/filename')

statvfs.f_frsize * statvfs.f_blocks     # Size of filesystem in bytes
statvfs.f_frsize * statvfs.f_bfree      # Actual number of free bytes
statvfs.f_frsize * statvfs.f_bavail     # Number of bytes available for users

WINDOWS

对于 Windows,您可以使用 wmi 模块或使用 ctypes

wmi

import wmi
c = wmi.WMI ()
for d in c.Win32_LogicalDisk():
    print(d.Caption, d.FreeSpace, d.Size, d.DriveType)

ctypes

import ctypes
import os
# get directoryname from the file example:--> dirname = os.path.dirname() 
free_bytes = ctypes.c_ulonglong(0)
ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(dirname), None, None, ctypes.pointer(free_bytes))
print(free_bytes.value / 1024 / 1024)

【讨论】:

在 python 3 中使用fstatvfsstatvfs 已被删除。 这似乎只在 Unix 上可用?我也需要一种在 Windows 上使用它的方法。 好的,问题是我的文件名类似于 \\.\d:ctypes 方法对此不起作用。我猜 wmi 有效,但我必须解析输出。所以,基本上 \\.\d: 是一个我可以用 os.open() 打开的文件,但我无法获得它的大小...... 对 Python 2 和 3 使用 os.statvfs。令人困惑的是,Py2 statvfs 模块已被删除,而不是 os 方法。【参考方案2】:

如果不利用 Python Win32 API,我认为这无法正确完成。

这里有一个Python Recipe (GitHub) 可以快速计算文件夹或卷的大小。它使用win32file.FindFilesW() 函数有效地计算文件夹或卷的总大小。它还可以处理需要截断尺寸或沿路径遇到错误的情况。

我已将函数转换为 Python 3:

## http://code.activestate.com/recipes/572179-quickly-calculate-folder-or-volume-size/
import win32file as _win32file
import sys as _sys

class FolderSize:
    """
    This class implements an efficient technique for
    retrieving the size of a given folder or volume in
    cases where some action is needed based on a given
    size.

    The implementation is designed to handle situations
    where a specific size is desired to watch for,
    in addition to a total size, before a subsequent
    action is taken. This dramatically improves
    performance where only a small number of bytes
    are sufficient to call off a search instead of
    waiting for the entire size.

    In addition, the design is set to handle problems
    encountered at points during the search, such as
    permission errors. Such errors are captured so that
    a user could further investigate the problem and why
    it occurred. These errors do not stop the search from
    completing; the total size returned is still provided,
    minus the size from folders with errors.

    When calling a new search, the errors and total size
    from the previous search are reset; however, the stop
    size persists unless changed.
    """

    def __init__(self):

        # This is the total size returned. If a stop size
        # is provided, then the total size will be the last
        # bytes counted after the stop size was triggered.
        self.totalSize = 0

        # This mapping holds any errors that have occurred
        # during the search. The key is the path name, and
        # its value is a string of the error itself.
        self.errors = 

        # This is the size where the search will end. The default
        # is -1 and it represents no stop size.
        self._stopSize = -1

        # This prints verbose information on path names.
        self.verbose = 0

    def enableStopSize(self, size=0):
        """
        This public method enables the stop size
        criteria. If the number of bytes thus far
        calculated exceeds this size, the search is
        stopped.

        The default value is zero bytes and means anything
        greater will end the search.
        """

        if type(size) != int:
            print("Error: size must be an integer")
            _sys.exit(1)

        self._stopSize = size

    def disableStopSize(self):
        """
        This public method disables the stop size
        criteria. When disabled, the total size of
        a folder is retrieved.
        """

        self._stopSize = -1

    def showStopSize(self):
        """
        This public method displays the current
        stop size in bytes.
        """

        print((self._stopSize))

    def searchPath(self, path):
        """
        This public method initiates the process
        of retrieving size data. It accepts either
        a UNC or local drive path.
        """

        # Reset the values on every new invocation.
        self.totalSize = 0
        self.errors = 

        self._getSize(path)

    def _getSize(self, path):
        """
        This private method calculates the total size
        of a folder or volume, and accepts a UNC or
        local path.
        """

        if self.verbose: print(path)

        # Get the list of files and folders.
        try:
            items = _win32file.FindFilesW(path + "\\*")
        except _win32file.error as details:
            self.errors[path] = str(details[-1])
            return

        # Add the size or perform recursion on folders.
        for item in items:

            attr = item[0]
            name = item[-2]
            size = item[5]

            if attr & 16:
                if name != "." and name != "..":
                    self._getSize("%s\\%s" % (path, name))

            self.totalSize += size

            if self._stopSize > -1:
                if self.totalSize > self._stopSize:
                    return

if __name__ == "__main__":

    # Get the size of entire folder.
    sizer = FolderSize()
    sizer.searchPath(r"D:\_audiobooks")
    print(sizer.totalSize)

    # Enable stop size (in bytes). Default is zero if no arg provided.
    sizer.enableStopSize(1024)
    sizer.searchPath(r"D:\_audiobooks")
    if sizer.totalSize > 1024:
        print("The folder meets the criteria.")
    elif sizer.totalSize == 0:
        print("The folder is empty.")
    else:
        print("The folder has some data but can be skipped.")

    # If the total size is zero, make sure no errors have occurred.
    # It may mean the initial path failed. Otherwise, errors are always from
    # subfolders.
    if sizer.totalSize == 0 and sizer.errors:
        print(sizer.errors)

如果您希望输出更易于阅读,还有另一个Python Recipe 供您使用(请参阅also):

print(bytes2human(sizer.totalSize))
3.9 G

【讨论】:

【参考方案3】:

使用psutil模块

import psutil

disk = psutil.disk_usage('/')

print(disk.total / (1024.0 ** 3))

【讨论】:

以上是关于python获取卷或物理驱动器的文件大小的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Python 会找到与 Windows 不同的文件大小?

如何确定 Windows 中的扇区大小?

了解硬盘扇区大小

确定文件大小时的Python无限循环

如何在没有 pushd 的情况下获取 UNC 路径上的文件大小?

Python:如何获取 PyQt5 中选定文件的文件大小?