登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> CLQ工作室开源代码 >> 主题: [delphi7/lazarus]太长文件名无法在 delphi7 中查找出来的原因和解决办法     [回主站]     [分站链接]
标题
[delphi7/lazarus]太长文件名无法在 delphi7 中查找出来的原因和解决办法
clq
浏览(429) + 2020-06-09 20:30:02 发表 编辑

关键字:

[2020-06-09 22:06:41 最后更新]
[delphi7/lazarus]太长文件名无法在 delphi7 中查找出来的原因和解决办法

在目录中如果有一个文件名非常长,比如近 300 个中文字符,那么以下代码在 lazarus 下正常,而 delphi7 则只能找到部分文件名。
经过调试,发现 GetLastError 的结果是 234 - "有更多数据可用",而如果没有文件的话实际上是 18 - "没有更多文件"。仔细查看了实现代码,基本上可以确定是接收文件名的缓冲区不够造成的,而这个问题还不能简单地通过加大缓冲区来得到。因为接收缓冲在 windows api 的接口中是定死长度的。



//遍历目录
var
_count:Integer = 0;

procedure FindFiles2(path: string; findDir:Boolean; findSub:Boolean=False);
var
searchRec: TSearchRec;
found: Integer;
tmpStr: string;
curDir: string;
dirs: TStringList;
pszDir: PChar;
fn:string;


begin

//加上搜索后缀,得到类似'c:\*.*' 、'c:\windows\*.*'的搜索路径
tmpStr := path + '*.*';
//在当前目录查找第一个文件、子目录
found := FindFirst(tmpStr, faAnyFile, searchRec);
while found = 0 do //找到了一个文件或目录后
begin
fn := path + searchRec.Name;

if (searchRec.Name <> '.') and (searchRec.Name <> '..') then
begin
//如果找到的是个目录
if ((searchRec.Attr and faDirectory) <> 0) then
begin

end
else//如果是文件
begin
//ListAdd(searchRec, fn);//fileList.Add(fn);
_count := _count + 1;
end;
end;

//查找下一个文件或目录
found := FindNext(searchRec);
end;

//释放资源
FindClose(searchRec);
ShowMessage(IntToStr(_count));
end;

----------------------------------------------------------------
d7 所用的函数实际上是 FindNextFileA 它的接收缓冲区如下

_WIN32_FIND_DATAA = record
dwFileAttributes: DWORD;
ftCreationTime: TFileTime;
ftLastAccessTime: TFileTime;
ftLastWriteTime: TFileTime;
nFileSizeHigh: DWORD;
nFileSizeLow: DWORD;
dwReserved0: DWORD;
dwReserved1: DWORD;
cFileName: array[0..MAX_PATH - 1] of AnsiChar;
cAlternateFileName: array[0..13] of AnsiChar;
end;

const
MAX_PATH = 260;

而 lazarus 的则是 unicode 版本,即

WIN32_FIND_DATAW = record
dwFileAttributes : DWORD;
ftCreationTime : FILETIME;
ftLastAccessTime : FILETIME;
ftLastWriteTime : FILETIME;
nFileSizeHigh : DWORD;
nFileSizeLow : DWORD;
dwReserved0 : DWORD;
dwReserved1 : DWORD;
cFileName : array[0..(MAX_PATH)-1] of WCHAR;
cAlternateFileName : array[0..13] of WCHAR;
end;

所以缓冲区要大一倍。

不过奇葩的是 vs2010 是 unicode 版本的情况下,搜索的结果居然和 delphi7 一样! 所以恐怕还有其他的原因。






clq
2020-06-09 21:49:40 发表 编辑

修改后的代码已放到 delphi_lost 项目中,地址

https://github.com/clqsrc/delphi_lost

主要是替换 SysUtils 中的同名函数。d7 中就是替换为 W 结尾的同名 unicode 版本函数就行了,而 vs2010 中的问题是什么呢,为什么 unicode 版本中也有错?估计各位喜欢 vc 的用户要自己找原因了,也许显示调用 W 版本函数可以解决,反而我测试的 unicode 编译版本是不行的。代码直接来自 baidu 百科,如下:


// vct1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include
#include
#include
#include

//来自 https://baike.baidu.com/item/_findnext/4901199?fr=aladdin
int main2( void )
{
long Handle;
struct _finddata_t FileInfo;

system("mode con: CP SELECT=936"); // 选定代码页,显示简体中文,如果您的DOS可以正常显示简体中文可以不要这一句

//if((Handle=_findfirst("D:\\*.txt",&FileInfo))==-1L)

printf("没有找到匹配的项目\n");
else
{
printf("%s\n",FileInfo.name);

while(_findnext(Handle,&FileInfo)==0)
printf("%s\n",FileInfo.name);

_findclose(Handle);
}

//FindNextFile

DWORD err_no = GetLastError();
printf("errno: %d", err_no);

return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
main2();
//getchr();
return 0;
}


clq
2020-06-09 22:06:41 发表 编辑

仔细搜索了一下 msdn ,发现在另外一个函数 FindFirstFileExA function 的说明中有提到文件名长度受限制时要使用 unicode 版本。

https://docs.microsoft.com/zh-cn/windows/win32/api/fileapi/nf-fileapi-findfirstfileexa

----------------------------------------------------------------

lpFileName

The directory or path, and the file name. The file name can include wildcard characters, for example, an asterisk (*) or a question mark (?).

This parameter should not be NULL, an invalid string (for example, an empty string or a string that is missing the terminating null character), or end in a trailing backslash ().

If the string ends with a wildcard, period, or directory name, the user must have access to the root and all subdirectories on the path.

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to approximately 32,000 wide characters, call the Unicode version of the function (FindFirstFileExW), and prepend "\\?\" to the path. For more information, see Naming a File.
Tip Starting in Windows 10, version 1607, for the unicode version of this function (FindFirstFileExW), you can opt-in to remove the MAX_PATH character limitation without prepending "\\?\". See the "Maximum Path Limitation" section of Naming Files, Paths, and Namespaces for details.



总数:2 页次:1/1 首页 尾页  
总数:2 页次:1/1 首页 尾页  


所在合集/目录
遍历目录失败 更多



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1