我正在编写一个大量的ID3标签编辑器.ID3标签通常在mp3编码文件的开头,尽管较旧的(版本1)标签在最后.该应用程序旨在从命令行接受目录和帧ID列表,然后递归更新其找到的所有ID3标签的目录结构.用户可以另外选择删除所有旧的(版本1)标签.另一个选择是简单地显示当前标签,而不执行更新.该目录可能包含2个文件或200万个.如果用户意味着更新文件,我计划将整个文件加载到内存中,执行更新,然后保存(文件也可能被重命名).但是,如果用户只是打印当前的ID3标签,则加载整个文件似乎过多.所有文件可能是200mb.
我读过这个线程,这很有洞察力 – mmap() vs. reading blocks
所以我的问题是,最有效的方式去读取(),mmap()或一些组合?设计理念欢迎.
TIA,
安德鲁
编辑:我的理解是,mmap基本上将文件加载到内存中,并将其加载到虚拟内存子系统中.在我看来,VMM将在大多数系统上进行高度优化,因为它对于系统性能至关重要.
解决方法
这真的取决于你想做什么.如果所有你需要做的是跳到一个已知的偏移量并读出一个小标签,read()可能会更快(mmap()必须做一些相当复杂的内部会计).但是,如果您计划复制所有200mb的MP3,或者扫描出可能出现未知偏移的某些标签,那么mmap()可能会更快.
例如,如果您需要将整个文件向下移动几百个字节以插入ID3标签,则一个简单的方法是使用ftruncate()扩展文件,将文件缩小,然后将memmove()的内容缩小为位.但是,如果您的程序在运行时崩溃,则会毁坏该文件.您也可以将文件的内容复制到新文件中 – 这是另一个mmap()真正闪耀的地方;您可以简单地mmap()旧的文件,然后使用一个write()将其所有数据复制到新文件中.
简而言之,如果您在传输的总字节数方面做了大量的IO,那么mmap()很棒这是因为它减少了所需的副本数量,并且可以显着减少读取缓存数据所需的内核条目数.但是,mmap()需要至少两次内核访问(如果在完成之后清理映射,则需要三次),并执行一些复杂的内部内核计费,因此固定开销可能很高.
另一方面,read()涉及额外的内存到内存副本,因此对于大型I / O操作可能是低效的,但是很简单,因此固定开销相对较低.简而言之,对于大批量I / O,使用mmap()和read()或pread()来进行一次性小I / O.