文件名截断为仅显示第一个字符

时间:2012-11-19 08:58:16

标签: c++ winapi file-io

我在MSDN上关注如何列出目录中的文件{我正在使用当前目录)this guide。在我的情况下,我需要将信息放在我的数据包的消息部分(大小为1016的字符数组)中,以将其发送到客户端。当我在客户端和服务器上打印packet.message时,只显示文件名的第一个字符。怎么了?以下是相关代码部分的片段:

WIN32_FIND_DATA f;
HANDLE h = FindFirstFile(TEXT("./*.*"), &f);
string file;
int size_needed;
do
{
    sprintf(packet.message,"%s", &f.cFileName);
    //Send packet
} while(FindNextFile(h, &f));

3 个答案:

答案 0 :(得分:5)

这通常是由于广泛的字符串被错误地视为ASCII字符串引起的。构建针对UNICODE,cFileName包含宽字符串,但sprintf()假设它是ASCII字符串。

FindFirstFile()将映射到FindFirstFileA()FindFirstFileW(),具体取决于构建是否针对UNICODE。

解决方案是明确使用FindFirstFileA()和ASCII字符串。

请注意,&

中不需要sprintf()
sprintf(packet.message, "%s", f.cFileName);

由于应用程序正在使用超出其控制范围的字符串(即文件名),我建议使用更安全的_snprintf()来避免缓冲区溢出:

/* From your comment on the question 'packet.message' is a 'char[1016]'
   so 'sizeof()' will function correctly. */
if (_snprintf(packet.message, sizeof(packet.message), "%s", f.cFileName) > 0)
{
}

答案 1 :(得分:4)

您使用的是FindFirstFile的Unicode版本,几乎可以保证,可以调用窄版本或更改打印的格式说明符。我个人会做前者:

WIN32_FIND_DATAA f;
HANDLE h = FindFirstFileA("./*.*", &f);
string file;
int size_needed;
do
{
    sprintf(packet.message,"%s", f.cFileName);
    //Send packet
} while(FindNextFileA(h, &f));
FindClose(h);

或者,您可以使用MBCS或常规字符进行编译。

答案 2 :(得分:2)

正如其他人所提到的,您正在调用FindFirstFile()的Unicode版本并将Unicode数据传递给Ansi sprintf()函数。 %s说明符期望Ansi输入。您可以在代码中解决此问题:

  1. 继续使用sprintf(),但将%s说明符更改为%ls,以便在写入邮件缓冲区时接受Unicode输入并将其转换为Ansi:

    sprintf(packet.message, "%ls", f.cFileName);
    

    这不太理想,因为它将使用本地机器的Ansi编码,这可能与接收机器使用的Ansi编码不同。

  2. 将您的消息缓冲区更改为使用TCHAR而不是char,然后切换为wsprintf()_stprintf()而不是sprintf()。与FindFirstFile()一样,它们会匹配TCHARTEXT()使用的任何字符格式:

    TCHAR message[1016];
    wsprintf(packet.message, TEXT("%s"), f.cFileName);
    

    或者:

    #include <tchar.h>
    
    _TCHAR message[1016];
    _stprintf(packet.message, _T("%s"), f.cFileName);
    
  3. 如果你必须使用char缓冲区,那么你应该接受来自API的Unicode数据并将其转换为UTF-8进行传输,然后接收器可以将其转换回Unicode并使用它根据需要。

    WIN32_FIND_DATAW f;
    HANDLE h = FindFirstFileW(L"./*.*", &f);
    if (h)
    {
        do
        {
            WideCharToMultiByte(CP_UTF8, 0, f.cFileName, lstrlenW(f.cFileName), packet.message, sizeof(packet.message), NULL, NULL);
           //Send packet
        } while(FindNextFile(h, &f));
        FindClose(h);
    }