{技术}{C++}为什么在FAT32分区上创建大文件花的时间比NTFS上多很多

27 views
Skip to first unread message

矿工

unread,
Sep 21, 2009, 8:30:05 AM9/21/09
to TopLanguage
RT
使用的方法如下:
Cfile.Open(Path,CFile::modeCreate | CFile::modeWrite);
Cfile.SetLength(m_FileSize);
Cfile.Close();

用此方法对NTFS分区操作一切正常,而且很快。但是对FAT32分区操作就会出现假死症状。现象如下:
1.程序假死。但是文件还是创建了。大小也一致。
2.在假死的过程中如果拔掉U盘,就会弹出“au unamed file was not found.”的对话框,程序恢复正常。
3.如果创建的文件比较小,那等一段时间后也是能恢复正常,文件也正常创建了。

经过分析了下,问题确定为CFile::close()函数里的CloseHandle(),搜了下了解到这是内核函数。也就是说是在关闭Cfile对
象时出现了问题。
假死时间的长短和创建文件的大小有关。我猜测是不是NTFS和FAT32在创建文件的方式不一样:
1. NFTS是直接创建了文件,划片区给它,然后不必填内容。
2. FAT32是创建了文件,划片区后,必须往里面填点东西。如果我不写,它就自己往里写。
这个思路自己验证了下,打开在两个分区创建的文件,结果是内面都是0。那就是说不是这个问题。

那问题是什么原因导致的呢?我记得以前用flashget,迅雷的时候,它们也会先创建一个和下载文件一样大的临时文件做缓冲区。它们又是什么做到能很
快的创建大文件呢?
小弟我才疏学浅,不知道是不是我自己在哪有个很低级的错误没发现,希望大虾能给于指教。

Hongzhang Liu

unread,
Sep 21, 2009, 9:51:27 PM9/21/09
to pon...@googlegroups.com
google sparse file (稀疏文件)

ntfs支持,fat32不支持。你的猜测部分正确。

2009/9/21 矿工 <cook...@gmail.com>:

Jia

unread,
Sep 21, 2009, 9:39:23 PM9/21/09
to TopLanguage

我记得以前 Fat32 的时候 下载大文件 FlashGet 也会假死吧

肖海彤

unread,
Sep 21, 2009, 10:52:32 PM9/21/09
to TopLanguage
缺省创建文件应该不是 sparse 的, 除非加上属性标志.
FAT32 创建文件的时候, 需要申请 fat 项, 填充 fat 项, 估计这个比较耗时.

但是我记得 NTFS, 如果目录不是具有压缩属性的, 创建软件也没有设置 sparse, 创建大文件也并不快 (多年没有用过 fat32, 没
有对比了).

colprog

unread,
Sep 22, 2009, 1:59:34 AM9/22/09
to pon...@googlegroups.com
好像是有个trick,建一个小文件,然后打开,设置文件指针,然后关闭。
好像这样是很快的~

小黑

unread,
Sep 22, 2009, 12:55:49 AM9/22/09
to pon...@googlegroups.com
你说的压缩属性是不是在分区属性页里的压缩选项吗?我的NTFS分区没有选这个也能在瞬间创建大文件。还有你说的sparse估计我也没有设置。
PS:sparse在哪设?-_-!!

2009/9/22 肖海彤 <red...@gmail.com>

Bill Wung

unread,
Sep 22, 2009, 7:57:09 AM9/22/09
to pon...@googlegroups.com
So good a idea!

On 9/22/09, colprog <col...@gmail.com> wrote:
> 好像是有个trick,建一个小文件,然后打开,设置文件指针,然后关闭。
> 好像这样是很快的~
>

--
Sent from my mobile device

笑骂由人,洒脱自如!
心若冰清,天塌不惊!
http://www.iron-feet.cn

小黑

unread,
Sep 22, 2009, 10:28:42 AM9/22/09
to pon...@googlegroups.com
按照你说的改成这样:
file.Open(Path,CFile::modeCreate | CFile::modeWrite);
file.SetLength(10);
file.Close();
file.Open(Path,CFile::modeWrite);
file.Seek(m_FileSize,CFile::begin);
file.Write(_T("1"),1);
        file.Flush();
  file.SeekToBegin();
file.Close();

但是花的时间是一样的。只是现在花时间的由file.Close()改成file.Write(_T("1"),2),在内部体现的就是CloseHandle()换成WriteFile()。这又验证了,说明FAT32在创建文件的时候是需要向没有用过的但申请了的空间写入0. 
难道就没有一种方法可以快速的在FAT32分区上生成大文件呢?

另外,了解了下你们所说的稀疏文件不是我要的,稀疏文件是不占空间,只有用了才占。但我想要的是快速生成大文件,占用空间。

2009/9/22 colprog <col...@gmail.com>

小黑

unread,
Sep 22, 2009, 12:02:30 PM9/22/09
to pon...@googlegroups.com
又搜了下,确实FAT32是要写数据,NTFS可以不用。

从网上搜到的方法都试过,时间都差不多。这主要原因还是FAT32文件系统的关系。

但同时也了解到高深的方法:
1. 自己通过DeviceIoControl控制设备,然后自己解析文件系统,找出文件的目录入口,读引导扇区找出簇大小以及FAT表位置和个数,扫描FAT表找出足够多的为0的元素并连成链,同时修改FAT表的各个副本,把首簇号写入文件的目录入口并回写入磁盘,最后DeviceIoControl FSCTL_DISMOUNT_VOLUME,关闭设备句柄。
2.做一个磁盘驱动。Attach到磁盘设备上。应用程序使用不缓冲方式创建文件,向文件中写入数据。自定义一个IoControl,将应用程序分配的磁盘缓冲区地址传给驱动程序,驱动程序同时记录进程ID。驱动程序在IRP_MJ_WRITE中,判断进程ID和用户缓冲区的地址,当条件满足时,不执行写磁盘操作,直接返回成功。

这个两个方法太高深,我的能力不行。有高人这样玩过吗?

2009/9/22 小黑 <cook...@gmail.com>

Tiny fool

unread,
Sep 22, 2009, 9:38:50 PM9/22/09
to pon...@googlegroups.com
FAT32应该是有切实存在的问题,我觉得你最好转换一下思路。首先FAT32有一个尺寸限制4GB,所以你不用考虑,也无法考虑更大的文件。那么,我认为,你可以以最大极限4GB去设计程序。需要一次性生成一个大文件,一般来说,主要是多线程下载,p2p下载,一方面避免文件碎片,一方面方便程序设计。

那么,我建议你把10M或者更大的尺寸当作一个你的逻辑簇去考虑,生成一个4GB的文件,分400次完成,可以多线程进行。同时,生成了多少个簇这个参数×10M,也就是你在生成文件期间,可以多线程下载的或者p2p下载的区域。这样,你的相应时间应该可以降到很低,而需求得到较好的满足。

小黑

unread,
Sep 23, 2009, 8:45:09 AM9/23/09
to pon...@googlegroups.com
你的这个方法只是给人感觉是减少了时间。但是硬盘只有一个,同样大小的文件,分小了存进去,跟一个大文件存进去都是一样的。硬盘写入速度不会提高,只能顺着一个一个存。

其实我不是写下载工具。只是想写个小程序能快速填满硬盘。测试在盘容量低,快满情况下的系统反应。

我想到一个非常诡异的方法:
其实在系统往FAT32分区生成文件填0前是已经分好空间的。如果此时拔掉U盘(我用U盘试的),文件一样是产生的。时间也花的很短。
那按照这个原理,如果在刚创建完文件,自己发出一个window消息,说U盘已经拔出,那系统就会停止写文件了。文件也是生成的。如果觉得系统会写入错误。那我们也可以截获这个消息。不让它出现。
大家觉得这方法靠谱不?能实现吗?

2009/9/23 Tiny fool <tiny...@gmail.com>

Tiny fool

unread,
Sep 23, 2009, 9:13:44 AM9/23/09
to pon...@googlegroups.com
不是感觉时间减少了,而是不阻塞。

2009/9/23 小黑 <cook...@gmail.com>



--
Tinyfool的开发日记 http://www.tinydust.net/dev/
myTwitter: http://twitter.com/tinyfool
Reply all
Reply to author
Forward
0 new messages