是否可以从特定行或字节开始读取文件。目前我使用这段代码读取一个文件的 4 个字节:
section .data
filename db "file.txt", 0
section .bss
read_data resb 4
section .text
global _start
_start:
mov rax, SYS_OPEN
mov rdi, filename
mov rsi, O_RDONLY
mov rdx, 0
syscall
push rax
mov rdi, rax
mov rax, SYS_READ
mov rsi, read_data
mov rdx, 4
syscall
mov rax, SYS_CLOSE
pop rdi
syscall
此代码始终读取前 4 个字节,但我想从文件的其他部分开始读取,例如中间部分。我需要添加或更改什么?
最佳答案
一个新打开的文件描述符从 position = 0 开始。如果你在一个循环中继续从同一个 fd
读取,你会得到连续的 block 。 (使用更大的缓冲区,如 8kiB,并在用户空间中循环双字,使用 read
返回的值作为上限!系统调用在 CPU 时间上非常昂贵。)
Is it possible to start reading a file from a specific line or byte.
- 字节:是
- 线路:没有。在 Unix/Linux 中,内核没有行起始字节偏移量索引或任何其他面向行的 API。例如,stdio
fgets
中的行处理纯粹是在用户空间中完成的。有一些历史操作系统使用基于记录的文件,但 Unix 文件是平面字节数组。 (它们可能有漏洞、未写入的范围和扩展属性……但主要文件内容的内核 API 仅使用字节偏移量进行操作)。
如果你想换行,读取一个大块并向前循环,直到你看到一些换行符。如果您还没有,请阅读另一个街区;重复直到找到所需行号的开始和结束,或者您点击 EOF。 x86-64 可以使用 pcmpeqb
/pmovmskb
/popcnt
一次高效地搜索 16 个字节(popcnt 需要 SSE4.2 或特定的 popcnt 功能位).
或者仅使用 SSE2,或者在针对大块进行优化时,使用 pcmpeqb
/psadbw
(针对全零)将 hsum 字节转换为 qwords/padd
。然后用一些标量代码检查你经常去多少行。或者保持简单并在 SIMD 向量中找到第一个换行符。
显然,缓慢而简单的选项是一个每次一个字节的循环,它计算 '\n'
个字符 - 如果您知道如何使用 SSE2 执行 strchr,那么向量化应该很简单使用上述建议进行搜索。
但如果您只想要一些特定的字节位置,您有两个主要选择:
在
read(2)
之前使用lseek(2)
进行搜索(参见@Nicolae Natea 的回答)使用 POSIX/Linux
pread(2)
从指定的偏移量读取,而不移动 fd 的文件偏移量以供将来的read
调用使用。 Linux 系统调用名称为pread64
(__NR_pread64 equ 17
来自asm/unistd_64.h
)ssize_t pread(int fd, void *buf, size_t count, off_t offset);
与read
的唯一区别是偏移量arg,第4个arg因此传入R10(不像用户空间函数调用约定那样的 RCX)。off_t
是一个 64 位类型,只是在 64 位代码中传入一个寄存器。
除了 .h
中的 pread64
名称外,asm 接口(interface)与 C 接口(interface)相比没有什么特别之处,它遵循标准的系统调用约定。 (自 Linux 2.1.60 以来就存在;在 glibc 的包装器使用 lseek 模拟它之前。)
您还可以执行其他操作,例如 mmap
或 preadv
系统调用,但如果您的位置已知,pread 正是您要查找的内容你想阅读。
关于linux - 从 x86 中的特定位置读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60687591/