谁的速度最快?
题目要求:生成一个512M大小的文件(文件的内容不管),用什么方法速度最快.
----------------------------------------------------
以下是本人的测试:
代码1:
var FHandle:THandle;
begin
self.FreeOnTerminate:=True;
self.OnTerminate:=Form1.createSucc;
FHandle:=CreateFile('testfile.wnd',
GENERIC_READ or GENERIC_WRITE , 0, nil, CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN, 0);
if FHandle=INVALID_HANDLE_VALUE then
raise Exception.Create('创建文件失败');
try
SetFilePointer(FHandle,1024*1024*512,nil,FILE_CURRENT);
if not SetEndOfFile(FHandle) then
raise Exception.Create('设置文件大小失败');
finally
CloseHandle(FHandle);
end;
end;
用时:15231毫秒
---------------------------------------------------
代码2:
var FileStream:TFilestream;
buf:array[0..1023] of byte;
i: integer;
Begin
FileStream:=TFilestream.create('testfile.wnd',fmCreate);
fillchar(buf,1024,'0');
for i:=0 to 1024*512 do
FileStream.Write(buf,1024);
FileStream.Free;
{
end;
用时:22332毫秒
--------------------------------------------------------
有兴趣的写出你的代码,并写出使用的时间.
问题点数:70、回复次数:47Top
1 楼g961681(技术庸人(情商太低))回复于 2005-01-07 15:55:24 得分 0
scTop
2 楼cocosoft()回复于 2005-01-07 15:57:54 得分 0
测试Top
3 楼surpassable()回复于 2005-01-07 15:58:18 得分 0
gz~~~~
和搂主差不多Top
4 楼linzhengqun(风。我回来了)回复于 2005-01-07 16:00:47 得分 0
等待......
^^Top
5 楼weidegong(weidegong)回复于 2005-01-07 16:09:51 得分 5
15秒会不会太长了点?我看bitcommet点了开始之后好像马上就分配了硬盘空间Top
6 楼linzhengqun(风。我回来了)回复于 2005-01-07 16:17:57 得分 0
楼上太对了,我就是因为这个原因,所以才在这里发这个贴的.
期待精彩的代码Top
7 楼fansnaf(投币一元)回复于 2005-01-07 16:22:29 得分 0
kanfenTop
8 楼constantine(飘遥的安吉儿)回复于 2005-01-07 16:48:06 得分 0
gzTop
9 楼zxthello(万有斥力)回复于 2005-01-07 17:18:22 得分 0
gz,
学习!Top
10 楼lzy6204(为了忘却的记忆)回复于 2005-01-07 17:33:04 得分 10
var
fh:integer;
begin
fh:=_lcreat('c:\temp',0);
_llseek(fh,512*1024*1024,FILE_BEGIN);
_lwrite(fh,nil,0);
_lclose(fh);
end
------------------
13秒
估计是我的机子速度快吧,估计快不了多少
Top
11 楼terrytzq(边缘)回复于 2005-01-07 17:36:12 得分 5
var FileStream:TFilestream;
Begin
FileStream:=TFilestream.create('testfile.wnd',fmCreate);
filestream.size:=512*1024*1024;
FileStream.Free;
{
Top
12 楼terrytzq(边缘)回复于 2005-01-07 17:37:41 得分 0
用时不知道!
应该快吧。Top
13 楼terrytzq(边缘)回复于 2005-01-07 17:46:36 得分 0
我还有一种方法可以创建 max(int64)GB 大小的文件用时比你们都小.
不是吹牛.....Top
14 楼ehom(?!)回复于 2005-01-07 17:55:28 得分 10
var
F: HFILE;
begin
F := FileCreate('C:\Test.tmp', 0);
SetFilePointer(F, 1024 * 1024 * 512, nil, FILE_BEGIN);
SetEndOfFile(F);
FileClose(F);
end;Top
15 楼ehom(?!)回复于 2005-01-07 17:57:24 得分 0
时间太短,无法精确计算,十几毫秒到一百多豪秒均有可能,一般小于100Top
16 楼web700(*FS*的小狗腿子)回复于 2005-01-07 17:59:47 得分 0
学习.Top
17 楼ehom(?!)回复于 2005-01-07 18:03:15 得分 0
呵呵,当然不是吹牛,MSDN里都写的很清楚啊~~~
Although the parameter lpDistanceToMoveHigh is used to manipulate huge files, the value of this parameter should be set when moving files of any size. If it is set to NULL, then lDistanceToMove has a maximum value of 2^31–2, or 2 gigabytes less two. This is because all file pointer values are signed values. Therefore if there is even a small chance that the file will grow to that size, you should treat the file as a huge file and work with 64-bit file pointers. With file compression on NTFS, and sparse files, it is possible to have files that are large even if the underlying volume is not very large.
If lpDistanceToMoveHigh is not NULL, then lpDistanceToMoveHigh and lDistanceToMove form a single 64-bit signed value. The lDistanceToMove parameter is treated as the low-order 32 bits of the value, and lpDistanceToMoveHigh as the upper 32 bits. Thus, lpDistanceToMoveHigh is a sign extension of lDistanceToMove.
To move the file pointer from zero to 2 gigabytes, lpDistanceToMoveHigh must be set to either NULL or a sign extension of lDistanceToMove. To move the pointer more than 2 gigabytes, use lpDistanceToMoveHigh and lDistanceToMove as a single 64-bit quantity. For example, to move in the range from 2 gigabytes to 4 gigabytes set the contents of lpDistanceToMoveHigh to zero, or to –1 for a negative sign extension of lDistanceToMove.
To work with 64-bit file pointers, you can declare a LONG, treat it as the upper half of the 64-bit file pointer, and pass its address in lpDistanceToMoveHigh. This means you have to treat two different variables as a logical unit, which is error-prone. The problems can be ameliorated by using the LARGE_INTEGER structure to create a 64-bit value and passing the two 32-bit values by means of the appropriate elements of the union.
It is conceptually simpler and better design to use a function to hide the interface to SetFilePointer. To do so, use something like this:
__int64 myFileSeek (HANDLE hf, __int64 distance, DWORD MoveMethod)
{
LARGE_INTEGER li;
li.QuadPart = distance;
li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
li.QuadPart = -1;
}
return li.QuadPart;
}
Top
18 楼ehom(?!)回复于 2005-01-07 18:04:42 得分 0
上面的li.LowPart, &li.HighPart在Delphi里就是
在Delphi里就是
var
Size: Int64;
Int64Rec(Size).Lo, @Int64Rec(Size).HiTop
19 楼terrytzq(边缘)回复于 2005-01-07 18:10:48 得分 0
我的不是这种方法。要简单多了Top
20 楼ehom(?!)回复于 2005-01-07 18:17:38 得分 0
呵呵,至少你上面用TFileStream就完全是一会事~~~
只是直接调API,理论上效率会高那么一点点,当然一般忽略不计Top
21 楼ygflydream(飞飞)回复于 2005-01-07 18:24:46 得分 0
up!Top
22 楼linzhengqun(风。我回来了)回复于 2005-01-07 18:37:37 得分 0
ehom的方法用时14841,不信你自己试一下,不会差很多的.
其实这段和我的代码1是差不多的.Top
23 楼linzhengqun(风。我回来了)回复于 2005-01-07 18:42:36 得分 0
用过bitcommet都知道,当他下载一个文件时,它会先生成一个和要下载的文件大小相同的临时文件.
它生成的速度相当快.
当上面的代码测试之后,似乎都没有办法达到要求,是为什么呢???//Top
24 楼linzhengqun(风。我回来了)回复于 2005-01-07 18:43:57 得分 0
terrytzq(边缘):
为什么不把你的代码贴出来和大家共享呢.Top
25 楼alphax(豪言壮语的乌鸦)回复于 2005-01-07 18:54:27 得分 10
如果是ntfs 5以上的文件系统,可以用sparse文件
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to a file
FSCTL_SET_SPARSE, // dwIoControlCode
NULL, // lpInBuffer
0, // nInBufferSize
NULL, // lpOutBuffer
0, // nOutBufferSize
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
然后设置文件尾就可以了
procedure ForExample;
var
F: TFileStream;
Dummy, FSFlags: DWORD;
begin
if GetVolumeInformation('C:\', nil, 0, nil, Dummy, FsFlags, nil, 0)
and ((FSFlags and FILE_SUPPORTS_SPARSE_FILES) <> 0) then
begin
F := TFileStream.Create('C:\test.data', fmCreate);
try
DeviceIoControl(F.Handle, FSCTL_SET_SPARSE, nil, 0, nil, 0, Dummy, nil);
F.Size := 1024*1024*512;
finally
F.Destroy();
end;
end;
end;
Top
26 楼alphax(豪言壮语的乌鸦)回复于 2005-01-07 18:57:03 得分 0
不过如果只是分配文件大小其实没有什么意义,因为如果实际提交的时候没有足够的磁盘空间,写操作也是失败的Top
27 楼ehom(?!)回复于 2005-01-07 19:03:26 得分 0
原来你是用Fat32,那就没办法了~~~
BitCommet能一次性生成和下载文件等大的空文件?其实那是错觉,刚开始文件大小只是0,然后逐步加大到和要下载文件等大的.Top
28 楼linzhengqun(风。我回来了)回复于 2005-01-07 19:18:51 得分 0
我认真看了一下,Bt在还没有连接成功时,它是0,但一旦连接成功后,它就突然变得和要下载的文件一样大了。
如果它是逐步加大,应该可以看到它正一步步变大才对,怎么能突然变得和下载文件一样大呢?
一直不懂。
Top
29 楼maming2003(關機.睡覺!)回复于 2005-01-07 19:19:49 得分 0
关注Top
30 楼maming2003(關機.睡覺!)回复于 2005-01-07 19:22:13 得分 0
var
F: HFILE;
begin
F := FileCreate('C:\Test.tmp', 0);
SetFilePointer(F, 1024 * 1024 * 512, nil, FILE_BEGIN);
SetEndOfFile(F);
FileClose(F);
end;
--------------------------------------------------------------
这个,速度快Top
31 楼Hozaka(空虚的狼)回复于 2005-01-08 09:10:11 得分 0
FlashGet 如果设置“获得文件大小后立即申请磁盘空间”,那么就是生成一个和目标一样大的文件,如果没有设置就是逐步加大。而且申请空间(就是生成文件)速度也很快,1G的文件才几秒。
一样期待代码中……Top
32 楼Hozaka(空虚的狼)回复于 2005-01-08 09:11:16 得分 0
另外,大家有没有想过,那10几秒的时间都用在什么地方了?哪里用掉的时间最多?我想可能对解决问题有帮助,哈哈~~
:)Top
33 楼linzhengqun(风。我回来了)回复于 2005-01-08 09:20:54 得分 0
我的是FAT格式,时间几乎用在
SetEndOfFile(F);这一个函数上。Top
34 楼linzhengqun(风。我回来了)回复于 2005-01-08 09:24:03 得分 0
如果没有办法,就能找会汇编了,对文件分配表进行操作Top
35 楼Hozaka(空虚的狼)回复于 2005-01-08 09:46:25 得分 0
我的意思就是楼上的意思,直接修改文件分配表,把结束标志划到指定的大小之后就可以了Top
36 楼linzhengqun(风。我回来了)回复于 2005-01-08 09:49:29 得分 0
去汇编版块问问。呵呵
希望有人既然讨论Top
37 楼ahjoe(强哥)回复于 2005-01-08 14:02:08 得分 10
procedure TForm1.Button1Click(Sender: TObject);
var
fs: TFileStream;
b: Byte;
timecnt: Integer;
begin
timecnt := GetTickCount();
fs := TFileStream.Create('F:\ABCD.TST', fmCreate);
fs.Position := 512*1024*1024-1;
fs.Write(b, sizeof(b));
fs.Free();
timecnt := GetTickCount() - timecnt;
Application.MessageBox(PChar('Use time: '+inttostr(timecnt)), 'OK', MB_OK);
end;
耗时如下
FAT32: 11607
未压缩的NTFS: 1.492
压缩的NTFS: 0Top
38 楼ahjoe(强哥)回复于 2005-01-08 14:03:39 得分 0
上面写错了
耗时如下
FAT32: 11607
未压缩的NTFS: 1492
压缩的NTFS: 0
Top
39 楼ly_liuyang(Liu Yang LYSoft http://lysoft.7u7.net)回复于 2005-01-08 14:21:22 得分 0
本质都是API做的
直接访问FileSystem当然最快,但着实不容易实现
http://lysoft.7u7.netTop
40 楼Kshape(C/C++初学者~~~~)回复于 2005-01-08 15:10:54 得分 0
楼上说的
直接访问filesystem当然很快了Top
41 楼linzhengqun(风。我回来了)回复于 2005-01-09 10:08:04 得分 0
以下这个代码是我试过最快的了:
var hf:HFile;
begin
hf:= CreateFile('test.tmp', GENERIC_WRITE, FILE_SHARE_WRITE nil,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
SetFilePointer(hf, 1024*1024*512, nil, FILE_BEGIN);
SetEndofFile(hf);
FlushFileBuffers(hf);
end;
用时是100毫秒。
原因是没有加入CloseHandle(hf),如果加入CloseHandle,则又回到上面那个速度了--十几秒钟。
Top
42 楼liumazi(刘麻子)回复于 2005-01-09 11:10:20 得分 20
不错,这正是我在大富翁论坛所贴的代码:
function CreateTempFile(const FileName: string; FileSize: Integer): Integer;
begin
Result := CreateFile(PChar(FileName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
SetFilePointer(Result, FileSize, nil, FILE_BEGIN);
SetEndofFile(Result);
FlushFileBuffers(Result);
end;
但是当文件句柄关闭的时候(手工调用CloseHandle或者进程退出),还是要很长时间,
因为这个时候会将内存中512M数据传到硬盘上.现在关键之所在,就是如何避免传输?
不过,顺便说一句,如果是作下载程序的话,最终我们还是需要把有用数据传到硬盘的,
所以,我觉得,可以通过上面这个函数返回的句柄操作文件,待下载完毕,再关闭句柄.Top
43 楼liumazi(刘麻子)回复于 2005-01-09 11:27:02 得分 0
继续关注此题,欢迎大家来此讨论: http://www.delphibbs.com/delphibbs/dispq.asp?lid=2954938Top
44 楼lemon_wei(研究BT,做好P2P)回复于 2005-01-09 11:44:12 得分 0
关注Top
45 楼fsybaby(!报峰语)回复于 2005-01-09 11:50:47 得分 0
Guan zhuTop
46 楼linzhengqun(风。我回来了)回复于 2005-01-09 12:40:01 得分 0
对,上面那个代码是从刘麻子老兄得来的。希望有人发表高见。
我的意思是围绕一个特定大小临时文件,用多线程的方法,将这个文件填充成要下载的文件。
大家可以围绕这个问题讨论,就是有点像FastGet那样就对了。Top
47 楼jinjazz(近身剪)回复于 2005-01-10 09:00:11 得分 0
家里adsl猫坏了,今天才看到,我试了一下closefile用了10秒钟Top





