【问题标题】:Query size of block device file in PythonPython中块设备文件的查询大小
【发布时间】:2010-05-05 13:30:51
【问题描述】:

我有一个 Python 脚本,用于读取标记不可读扇区的文件(通常来自光学介质),以允许重新尝试在不同的光学阅读器上读取所述不可读扇区。

我发现我的脚本不适用于块设备(例如 /dev/sr0),以便创建包含的 ISO9660/UDF 文件系统的副本,因为 os.stat().st_size 为零。该算法目前需要提前知道文件大小;我可以改变它,但问题(知道块设备大小)仍然存在,这里没有回答,所以我打开这个问题。

我知道以下两个相关的 SO 问题:

因此,我在问:在 Python 中,如何获取块设备文件的文件大小?

【问题讨论】:

    标签: python linux filesize device


    【解决方案1】:

    我已经达到的“最干净”(即不依赖于外部卷和最可重用)的 Python 解决方案是打开设备文件并在末尾查找,返回文件偏移量:

    def get_file_size(filename):
        "Get the file size by seeking at end"
        fd= os.open(filename, os.O_RDONLY)
        try:
            return os.lseek(fd, 0, os.SEEK_END)
        finally:
            os.close(fd)
    

    【讨论】:

    • 由于两周后没有其他答案,我选择了自己的答案。
    【解决方案2】:

    基于 Linux 的 ioctl 解决方案:

    import fcntl
    import struct
    
    device_path = '/dev/sr0'
    
    req = 0x80081272 # BLKGETSIZE64, result is bytes as unsigned 64-bit integer (uint64)
    buf = b' ' * 8
    fmt = 'L'
    
    with open(device_path) as dev:
        buf = fcntl.ioctl(dev.fileno(), req, buf)
    bytes = struct.unpack('L', buf)[0]
    
    print device_path, 'is about', bytes / (1024 ** 2), 'megabytes'
    

    当然,其他 unix 会有不同的 req、buf、fmt 值。

    【讨论】:

      【解决方案3】:

      另一种可能的解决方案是

      def blockdev_size(path):
          """Return device size in bytes.
          """
          with open(path, 'rb') as f:
              return f.seek(0, 2) or f.tell()
      

      or f.tell() 部分是为了 Python 2 的可移植性——file.seek() 在 Python 2 中返回 None。

      魔术常数2 可以替换为io.SEEK_END

      【讨论】:

      • 感谢您的回答。基本上最后一行在 Python 2 和 3 中都可以是return f.seek(0, 2) or f.tell()。你说与哪一个相比“更清洁的解决方案”?
      • 确实如此。谢谢!与“most clean” 相比(你的)。
      • @tzot 我已经改写了第一句话并应用了您的“或”建议。谢谢!
      • 我的假设是 f.seek() 返回与 f.tell() 相同 - “返回一个整数,给出文件对象在文件中的当前位置,表示为从开头开始的字节数二进制模式下的文件和文本模式下的不透明数字”,但这实际上不在 Python 3 文档中。什么是“不透明”数字?
      【解决方案4】:

      在 Linux 中,有/sys/block/${dev}/size,即使没有 sudo 也可以读取。要获得/dev/sdb 的大小,只需执行以下操作:

      print( 512 * int(open('/sys/block/sdb/size','r').read()) )
      

      另见https://unix.stackexchange.com/a/52219/384116

      【讨论】:

        【解决方案5】:

        试图从另一个答案中适应:

        import fcntl
        c = 0x00001260 ## check man ioctl_list, BLKGETSIZE
        f = open('/dev/sr0', 'ro')
        s = fcntl.ioctl(f, c)
        print s
        

        我手头没有合适的计算机来测试这个。我很想知道它是否有效:)

        【讨论】:

        • 我对@9​​87654322@ 和fd = os.open 都进行了尝试(因为fcntl.ioctl 需要文件描述符,尽管它可能在Python 文件对象上调用.fileno())。在这两种情况下,fcntl.ioctl 都引发了 IOError: [Errno 14] Bad address
        猜你喜欢
        • 2015-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-17
        • 1970-01-01
        • 2018-12-26
        • 2015-09-12
        • 2020-03-03
        相关资源
        最近更新 更多