当mmap()文本文件时,如此
int fd = open("file.txt", O_RDWR);
fstat(fd, &sb)
char *text = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
文件内容直接映射到内存中,text
它不包含NUL终结符,因此使用普通字符串函数对其进行操作将不安全。在Linux(至少)上,未使用页面的剩余字节是零填充的,因此在文件大小不是页面大小的所有情况下,有效地获得NUL终止符。
但依赖于那种感觉很脏并且其他mmap()
实现(例如,在FreeBSD中,我认为)不会零填充部分页面。映射文件是页面大小的倍数也将缺少NUL终结符。
有合理的解决方法或添加NUL终止符吗?
我考虑过的事情
strn*()
个函数并跟踪到缓冲区末尾的距离。
str*()
函数没有strn*()
对应的内容,例如strstr
。str*()
函数MAP_FIXED
不是线程安全的;无论如何,似乎是一个可怕的黑客mmap()
一个额外的字节,使地图可写,并写入NUL终结符。 OpenGroup的mmap man page表示您可以使映射大于对象的大小,但访问实际映射对象之外的数据将生成SIGBUS
。
str*()
函数SIGBUS
,这可能意味着发生了其他事情。我真的不确定写NUL终结器会起作用吗?ftruncate()
一个字节。
str*()
函数; ftruncate()
会将NUL字节写入新分配的区域mmap()
实现的问题read()
将文件放入malloc()
内存,忘记mmap()
malloc()
和额外字节
mmap()
解决方案#1似乎通常是最好的,只需要阅读文本功能的一些额外工作。
是否有更好的替代方案,或者这些是最佳解决方案?我没有考虑过这些解决方案的某些方面是否会使它们或多或少具有吸引力?
答案 0 :(得分:3)
我建议在这里进行范式转换。
您正在查看整个Universe,其中包含定义文本的'\ 0'分隔字符串。不要以这种方式看世界,为什么不尝试查看将文本定义为由开始和结束迭代器定义的序列的世界。
您mmap
您的文件,然后最初设置开始迭代器,将其称为beg_iter
到mmap-ed段的开头,并将结束迭代器称为end_iter
,以mmap-ed段中最后一个字节后面的第一个字节,或beg_iter+number_of_pages*pagesize
,然后直到
A)end_iter
等于beg_iter
或
B)beg_iter[-1]
不是空字符,那么
C)递减end_iter
,然后返回步骤A.
完成后,您将拥有一对迭代器,开始迭代器值以及定义文本字符串的结束迭代器值。
当然,在这种情况下,你的迭代器是普通的char *
,但这真的不是很重要。重要的是,现在您可以使用C ++标准库中的一组丰富的算法和模板,这可以让您实现许多复杂的操作,包括可变的(如std::transform
)和非可变的, (如std::find
)。
Null终止的字符串实际上是普通C语言的延续。对于C ++,以null结尾的字符串有些过时,而且平凡。现代C ++代码应使用std::string
个对象,以及由开始和结束迭代器定义的序列。
一个小脚注:你可能会发现更容易fstat()文件,并且得到文件的确切长度(以字节为单位),而不是弄清楚你在mmap-ing()中填充了多少NULL
填充,在mmap之前。然后你现在确切地知道很多已经被mmaped,你不必通过查看填充来进行逆向工程。