65.9K
CodeProject 正在变化。 阅读更多。
Home

WinFile

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.03/5 (6投票s)

2020年5月24日

MIT

5分钟阅读

viewsIcon

8912

downloadIcon

243

任何 :-) 你可以用 MS-Windows 文件做的事情。

引言

将它们集成到一个面向对象的类中。为什么?嗯,在大型项目中,各种文件操作函数会随着时间的推移而出现。有些可以处理“FILE*”指针,有些则必须处理Windows内核的HANDLE。你可以使用旧式的POSIX函数,如“fopen”(更可能的是“fopen_s”)和“fgets”、“fputs”或“getc”配合标准的FILE指针。但其他一些函数,如属性或文件时间,需要内核的HANDLE,而这个HANDLE可以通过“CreateFile”SDK函数获得,而不是使用“fopen”的对应函数。

在其他时候,你可能想使用标准的库ifstreamofstream接口,这会给你带来第三种文件接口。有时,这会让人非常困惑。而且,虽然有许多子函数,但处理这些函数的例程往往分散在代码中。

WinFile 作为函数集合

WinFile”项目最初是一个关于在MS-Windows系统上可以对文件进行操作的函数集合。这样可以使它们保持在一起。随着时间的推移,它不断发展,收集了更多的函数和技巧。好吧,你只需调用一个SDK函数,如“CopyFile”来复制文件,但你(或我)能记起使用“CopyFileEx”时可以使用的所有额外选项吗?WinFile类收集了所有这些技巧。这个函数需要FILE还是HANDLE?我以前在哪里见过这个技巧?

这里所有的一切都在一个接口中。

使用代码:最好的文档

最好的文档当然是项目“WinFile.h”中的接口文件。你可以在那里找到所有的方法和方法中使用的enum类型的参数。所以,请去看看那个文件!

这里是对WinFile你可以做什么的一个简明扼要的概括

  • 以测试/二进制模式打开,有或无共享或缓冲
  • 以文本或二进制模式读写
  • 读写单个字符并进行字符的“未读取”操作
  • 文件定位以进行随机访问
  • 移动、复制、删除、删除到回收站
  • 测试文件是否存在、可读和/或可写
  • 创建临时文件
  • 获取和设置属性
  • 获取和设置文件时间
  • 锁定和解锁文件或文件的部分
  • 文件名的操作以及通过对话框获取文件名
  • 目录操作,如创建路径和确保其存在
  • 用作共享内存虚拟映射文件
  • 使用Windows Shell的CSIDL_*特殊文件夹名称
  • 错误处理以及获取最后一个错误作为字符串
  • 消除文件开头的BOM(字节顺序标记)

性能和缓存

在此过程中,我遇到了一个障碍。性能!令人沮丧的是,发现以文本翻译模式读取字符串——将文件中的“\r\n”转换为单个“\n”——速度相当慢。在我的第一个版本中,这比“fgets(buffer,count,FILE)”慢了10倍以上。我对自己说,这可不行!那么,为什么会这么慢呢?

嗯,当然,当你用“fopen”或“fopen_s”打开文件并返回FILE指针时,后台会进行一些缓存。缓存文件的一部分总是比从文件HANDLE读取每个字符要快得多。

所以,我挽起袖子,开始在WinFile类中编写自己的缓冲区缓存。该缓存的第一版本可以轻松地为读取操作读取一个缓冲区,并返回缓存的字符串版本。哇。这速度快多了,即使是在SSD系统上。而且在实际的HDD上,由于移动的磁头和旋转的盘片,速度更快。

真正的挑战在于,不仅要能够写入缓存,还要在进行随机文件访问时同步缓存。在随机访问模式下读写意味着操作系统的“真实”文件指针与缓存缓冲区中的文件指针不同步。因此,我们必须时刻调整以刷新缓冲区并重新同步文件指针。

速度比较

在所有功能都正常工作后,我对与其他文件访问方法的比较感到好奇。我的“新宝宝”与“ifstream”接口相比如何?

好了:这是一个比较表(来自“main.cpp”中的测试程序编译而成)

(时间测量使用来自https://github.com/edwig/marlin的“HPFCounter”。)

除了SSD比HDD快(sic)这一事实外,我们从这个测试中可以学到的是,创建的WinFile缓存比从“fgets”FILE读取快得多(至少快两倍),并且比标准库ifstream快3倍!而当你多次运行测试时,这些时间相当一致。

这是一个决定性的比较吗?当然不是。有很多方法可以调整结果、驱动器、我们正在读取或写入的文件类型等等。标准库爱好者会指出,ifstream的缓冲区大小可以增加以获得更好的性能。你可以通过使用(ifstream).rdbuf()->pubsetbuf(buf,size)方法自己做到这一点。虽然这确实能在像Apple-OS和Linux这样的类Unix操作系统上获得更好的读取性能,但在MS-Windows上却没有任何效果。但也许有人会发现惊喜……

和平,不是战争

请务必!关于读取和写入文件的其他优化,有很多话可以讲。我从未打算挑起争论。

它还在不断发展

WinFile类还在不断发展。时不时地,我会在我专业工作的某个项目中发现一个技巧或函数,并将其添加到这个类中。

当前和最新版本也可以在https://github.com/edwig/WinFile找到。

历史

  • 2020年5月24日:初始版本
© . All rights reserved.