Python中查询块设备文件大小

发布于 2024-08-31 22:14:27 字数 509 浏览 7 评论 0原文

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

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

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

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

I have a Python script that reads a file (typically from optical media) marking the unreadable sectors, to allow a re-attempt to read said unreadable sectors on a different optical reader.

I discovered that my script does not work with block devices (e.g. /dev/sr0), in order to create a copy of the contained ISO9660/UDF filesystem, because os.stat().st_size is zero. The algorithm currently needs to know the filesize in advance; I can change that, but the issue (of knowing the block device size) remains, and it's not answered here, so I open this question.

I am aware of the following two related SO questions:

Therefore, I'm asking: in Python, how can I get the file size of a block device file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

姐不稀罕 2024-09-07 22:14:27

我所达到的“最干净”(即不依赖于外部卷并且最可重用)的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)

The “most clean” (i.e. not dependent on external volumes and most reusable) Python solution I've reached, is to open the device file and seek at the end, returning the file offset:

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)
紫罗兰の梦幻 2024-09-07 22:14:27

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 会有不同的值。

Linux-specific ioctl-based solution:

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'

Other unixes will have different values for req, buf, fmt of course.

情绪 2024-09-07 22:14:27

另一种可能的解决方案是

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

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

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

Another possible solution is

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() part is there for Python 2 portability's sake — file.seek() returns None in Python 2.

Magic constant 2 may be substituted with io.SEEK_END.

七颜 2024-09-07 22:14:27

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

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

另请参阅 https://unix.stackexchange .com/a/52219/384116

In Linux, there is /sys/block/${dev}/size that can be read even without sudo. To get the size of /dev/sdb simply do:

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

See also https://unix.stackexchange.com/a/52219/384116

情深如许 2024-09-07 22:14:27

此解决方案使用 lsblk(由 util-linux 提供)并且不需要 sudo:

import json
import subprocess

def get_device_size_bytes(device: str) -> int:
    output = subprocess.run(
        ["lsblk", device, "--json", "--bytes"], capture_output=True, check=True
    )
    dev_info = json.loads(output.stdout)
    size_bytes = dev_info["blockdevices"][0]["size"]
    return size_bytes

更短的解决方案仅从 lsblk 获取大小:

import subprocess

def get_device_size_bytes(device: str) -> int:
    output = subprocess.run(
        ["lsblk", device, "--output", "SIZE", "--bytes", "--noheadings", "--nodeps"],
        capture_output=True,
        check=True,
    )
    size = int(output.stdout.decode())
    return size

This solution uses lsblk (provided by util-linux) and does not require sudo:

import json
import subprocess

def get_device_size_bytes(device: str) -> int:
    output = subprocess.run(
        ["lsblk", device, "--json", "--bytes"], capture_output=True, check=True
    )
    dev_info = json.loads(output.stdout)
    size_bytes = dev_info["blockdevices"][0]["size"]
    return size_bytes

Shorter solution to only get size from lsblk:

import subprocess

def get_device_size_bytes(device: str) -> int:
    output = subprocess.run(
        ["lsblk", device, "--output", "SIZE", "--bytes", "--noheadings", "--nodeps"],
        capture_output=True,
        check=True,
    )
    size = int(output.stdout.decode())
    return size
时光暖心i 2024-09-07 22:14:27

尝试适应其他答案:

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

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

Trying to adapt from the other answer:

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

I don't have a suitable computer at hand to test this. I'd be curious to know if it works :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文