关于FileExists的再讨论(0分)

  • 主题发起人 主题发起人 dwwang
  • 开始时间 开始时间
D

dwwang

Unregistered / Unconfirmed
GUEST, unregistred user!
(关于MicroStar的"Delphi傻函数"的问题)
为了证明MicroStar的爱没有白白付出, ^_^
特对FileExists函数进行分析,望众位仁兄评判:
FileExists不能在一个目录里支持*.*,
并不是Delphi的Bug,而是设计者的考虑
与我们不同,或者说考虑不周罢了.
看了FileExists的源码就知道,它调用
FileAge,而该函数对于目录总是返回-1,
即"滤掉"了目录.FileExists对FileAge=-1
的文件返回False.
而任何一个子目录的第一个满足*.*条件的
文件总是 "."(大家不会忘记Dos的目录结构吧!)
它是一个目录,因此FileExits当然返回False.
-- 这也就是为什么根目录总是返回True的原因.
对于D盘以下的其它盘,则第一个文件不一定是什么
类型,因此返回值各异.
 
不愧为大虾风范,对问题总能精益求精。
 
(不是骂我吧?*_^)
我只是太喜欢Delphi了,有人说她两句不好,
我都难受,总想跟人家辩驳。
要是Inprise自己不争气,是Delphi的bug,
也就认了;不然,当然要为她平反昭雪!
希望继续付出你们的爱,为了永远的Delphi!
 
dwwang兄,看完下面这段程序,你可能要对Delphi咬牙切齿。
要知道,Delphi的确有不好的地方,下面这个错误至少在Delphi3.0-3.02中都
没有作过修改,至于D4,我没有试过。想来也差不多吧!
执行这段程序:
uses FmxUtils;
//c:/delphi3/demos/doc/filmanex
procedure TForm1.Button1Click(Sender: TObject);
begin
FmxUtils.copyfile('test.txt','m.txt');
end;

很显然,目的是要将test.txt复制成m.txt。相信用过dos的人都知道它的含义。
但是,执行的结果却将发生一个你意想不要的错误,大概会是:
cannot create file D:/program/m.txt/test.txt.
其中,d:/program是系统的当前目录。
这个奇怪的错误是如何产生的呢?
读FmxUtils.pas源码:
procedure CopyFile(const FileName, DestName: TFileName);
var ...
const ...
begin
Destination := ExpandFileName(DestName);
{ expand the destination path }
if HasAttr(Destination, faDirectory) then
{ if destination is a directory... }
Destination := Destination + '/' + ExtractFileName(FileName);
{ ...clone file name }
...
end;
//以上描述摘自源程序
一切可以理解,首先以当前目录生成一条目标路径,然后判定如果是目录,
则扩展成一个文件名。也就是处理如下两种情况(当然还有如目录/路径等):
1. CopyFile(aFile,aFullPath) ==> Copy aFile aFullPath+aFile
2. CopyFile(aFile,otherFile) ==> Copy aFile CurrentDir+aFile
问题出现了,HasAttr(Destination, faDirectory)并没有很好的工作:
入口参数m.txt是一个还不存在的文件,这时,HasAttr()却判定它具有
faDirectory属性!!!
再读HasAttr()函数,很简单:
function HasAttr(const FileName: string;
Attr: Word): Boolean;
begin
Result := (FileGetAttr(FileName) and Attr) = Attr;
end;
但问题正出在这儿!
FileGetAttr()这个函数出错(例如没有找到文件)时返回-1,即$FFFFFFFF,
这个值and任何值均为其本身,即Result := ($FFFFFFFF and Attr) = Attr
这样,函数返回值为True!——HasAttr()取一个不存在的文件/目录的任意属性
时,其返回值均为真!
结论是:
===========
HasAttr()函数写错了,它至少应该判定一次文件/目录是否存在;
或者是CopyFile()函数调用HasAttr()错了,它应该在调用前检查文件名有效性
修正方法:
===========
if HasAttr(Destination, faDirectory) then
...
一行的目的是判定Destination是否是目录,仅此而已。为此而写个HasAttr,
说明Borland公司中有个疯子!因为事实上他只需要调用一下DirectoryExists()
函数即可。
将上述语句改成if DirectoryExists(Destination) then
... 即可
其它:
===========
我是在写一个文件管理程序时遇到上述问题的,这使得我最终用另外的方法
实现了CopyFile()函数。
这个单元实际上是Delphi的经典单元,在Online help中多次提到。
该单元中的MoveFile()函数中存在同样的问题。
^-^
细细的读一下Delphi的源程序,许多人会哭鼻子的。好多地方不合理或隐含
着错误!甚至,我读到VCL源码时,都发现大量的错误。
一个惊人的消息,Delphi的Registry.pas(注册表管理)单元,隐含着两个逻
辑错,可以导致调用时将非法信息写入注册表。
(我所使用的是Delphi 3.x的最终修正版Delphi 3.02!)
 
FileExists 函数确实令人莫名其妙, 实际上用 FindFirst 就足够了, 非得费时的
去看一下 FileAge.
以前的 TP 及 Delphi 的早期版本都是通过检查 I/O 错误来实现的, 效率较高. 现
在改用 FindFirst 我想是为了不用改变 I/O 检验开关而不引发 Except 吧.
另外现在编程好像都不象以前那样注重系统的效率和合理地利用系统资源了, 调通了
就行了, 真是...
 
你们,你们想干什么!?
天哪!(悲痛欲绝状)
 
New Programmer principle:
need HardWare speed? find Inter.......
need SoftWare speed? find Borland.......
need source code? find internet......
need shutdown????????
please find microsoft......
--------writed by aimingoo
^-^
一个建议: 干脆大家在这个贴子下开始挖Delphi的臭虫算了。
 
虽然是0分,也要加给说好话的人 *_^
 
虽然是0分,也要加给说好话的人 *_^
 
如果这样那你可惨了你得分不被扣光拆怪("悲痛欲绝状 "you had said)
 
后退
顶部