【问题标题】:trouble manipulating wchar操作 wchar 的麻烦
【发布时间】:2018-09-12 03:13:37
【问题描述】:

我是 C++ 新手。我正在尝试列出目录中的文件。我正在使用Unicode。问题不是列出文件,而是用 wchar* 处理字符串和路径,我快疯了。这是我的测试代码:

#define UNICODE 1
#include <stdio.h>
#include <windows.h>
#include <wchar.h>


int wmain(int argc,wchar_t **argv){
    if (argc > 1){
        wchar_t* path=argv[1];
        wchar_t* pwc;
        int last_occurence;
        pwc=wcsrchr(path,L'\\');  
        last_occurence = pwc-path+1;
        int len = wcslen(path);
        if (last_occurence == len){
            //slash
        }else{
            //no slash
            wcscat(path,L"\\");
        }
        wcscat(path,L"*");

        WIN32_FIND_DATA FindData;
        HANDLE hSearch;
        hSearch = FindFirstFile(path , &FindData);
        if(hSearch == INVALID_HANDLE_VALUE){
            return -1;
        }else{
            // *** PROBLEM STARTS HERE
            wchar_t* filePath=NULL;
            do{
                wcscpy(filePath,path);
                wcscat(filePath,FindData.cFileName);
                wprintf(L"Path %s\n",filePath);
                memset(filePath, '\0', wcslen(filePath));
            // *** PROBLEM ENDS HERE
            }while( FindNextFile(hSearch, &FindData) > 0 );
            int ret = FindClose(hSearch);
            return 0;
        }
    }
}

当我运行已编译的应用程序时,它停止响应。我想做的是打印我传递给我的应用程序的路径 (c:\dir1\dir2) 并在其中附加文件 (file1,file2),如下所示:

c:\dir1\dir2\file1

c:\dir1\dir2\file2

如何解决这个问题?有最好的方法来做这样的事情吗?如果可能的话,我会保留 wchar 而不是 std 字符串

【问题讨论】:

  • 为什么不std::string
  • @GrantGarrison 在这种情况下你的意思是std::wstring
  • 你的调试器说了什么?
  • @Grant 没有真正的理由。我不喜欢 std::string 的语法。我想保留与旧 c 示例更相似的语法..
  • @LightnessRacesinOrbit 我在控制台中运行已编译的 exe。应用程序停止响应并且操作系统终止它而没有来自调试器的任何其他消息

标签: c++ string path wchar-t


【解决方案1】:

您的代码存在一些问题。

  • 您将"\\*" 连接到argv[1] 指向的内存,这很糟糕。您需要将pathwchar_t* 指针更改为wchar_t[] 数组,然后将wcscpy argv[1] 数据放入其中。

  • 您没有为filePath 分配任何内存,因此wcscpy()wcscat() 正在写入无效内存。您还需要将filePath 更改为wchar_t[] 数组,然后将wcscpy/wcscat 路径数据放入其中。

  • pathcFileNames 值组合在一起时,您也不会忽略串联的*

  • 你根本不需要memset()(尤其是因为你给了它错误的字节数)。

尝试类似的方法:

#define UNICODE 1
#include <stdio.h>
#include <windows.h>
#include <wchar.h>

int wmain(int argc, wchar_t **argv)
{
    if (argc < 2)
    {
        wprintf(L"Usage: \"%s\" path\n", argv[0]);
        return -1;
    }

    int len = wcslen(argv[1]);
    if (len >= MAX_PATH)
    {
        wprintf(L"Path is too long\n");
        return -1;
    }

    wchar_t path[MAX_PATH+1] = {};
    wcscpy(path, argv[1]);
    if ((len > 0) && (path[len-1] != L'\\'))
        wcscat(path, L"\\");

    wchar_t searchMask[MAX_PATH+2] = {};
    wcscpy(searchMask, path);
    wcscat(searchMask, L"*");

    WIN32_FIND_DATA FindData;
    HANDLE hSearch = FindFirstFileW(searchMask, &FindData);
    if (hSearch == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
        {
            wprintf(L"Error looking for first file\n");
            return -1;
        }
        wprintf(L"No files found\n");
    }
    else
    {
        wchar_t filePath[MAX_PATH*2];
        do
        {
            wcscpy(filePath, path);
            wcscat(filePath, FindData.cFileName);
            wprintf(L"Path %s\n", filePath);
        }
        while (FindNextFileW(hSearch, &FindData));

        if (GetLastError() != ERROR_NO_MORE_FILES)
        {
            FindClose(hSearch);
            wprintf(L"Error looking for next file\n");
            return -1;
        }

        FindClose(hSearch);
    }

    return 0;
}

尽管如此,您确实应该使用std::unique_ptrstd::wstring 类并让它们为您管理内存/资源。使用 C 库函数并不能帮助您学习 C++:

#define UNICODE 1
#include <windows.h>
#include <wchar.h>

#include <iostream>
#include <string>
#include <memory>

struct FindDeleter
{
    typedef HANDLE pointer;

    void operator()(HANDLE h)
    {
        if(h != INVALID_HANDLE_VALUE)
            FindClose(h);
    }
};

int wmain(int argc, wchar_t **argv)
{
    if (argc < 2)
    {
        std::wcerr << L"Usage: \"" << argv[0] << L"\" path" << std::endl;
        return -1;
    }

    std::wstring path = argv[1];
    if ((!path.empty()) && (path[path.length()-1] != L'\\'))
        path += L'\\';

    WIN32_FIND_DATA FindData;
    std::unique_ptr<HANDLE, FindDeleter> hSearch(FindFirstFileW((path + L"*").c_str(), &FindData));
    if (hSearch.get() == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
        {
            std::wcerr << L"Error looking for first file" << std::endl;
            return -1;
        }
        std::wcout << L"No files found" << std::endl;
    }
    else
    {
        do
        {
            std::wstring filePath = path + FindData.cFileName;
            std::wcout << L"Path " << filePath << std::endl;
        }
        while (FindNextFileW(hSearch.get(), &FindData));

        if (GetLastError() != ERROR_NO_MORE_FILES)
        {
            std::wcerr << L"Error looking for next file" << std::endl;
            return -1;
        }
    }

    return 0;
}

或者,如果您没有使用 C++11 编译器:

#define UNICODE 1
#include <windows.h>
#include <wchar.h>

#include <iostream>
#include <string>

class FindHandle
{
private:
    HANDLE m_hFind;

public:
    FindHandle(HANDLE hFind) : m_hFind(hFind) {}

    ~FindHandle()
    {
        if (m_hFind != INVALID_HANDLE_VALUE)
            FindClose(m_hFind);
    }

    HANDLE get() { return m_hFind; }
};

int wmain(int argc, wchar_t **argv)
{
    if (argc < 2)
    {
        std::wcerr << L"Usage: \"" << argv[0] << L"\" path" << std::endl;
        return -1;
    }

    std::wstring path = argv[1];
    if ((!path.empty()) && (path[path.length()-1] != L'\\'))
        path += L'\\';

    WIN32_FIND_DATA FindData;
    FindHandle hSearch(FindFirstFileW((path + L"*").c_str(), &FindData));
    if (hSearch.get() == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() != ERROR_FILE_NOT_FOUND)
        {
            std::wcerr << L"Error looking for first file" << std::endl;
            return -1;
        }
        std::wcout << L"No files found" << std::endl;
    }
    else
    {
        do
        {
            std::wstring filePath = path + FindData.cFileName;
            std::wcout << L"Path " << filePath << std::endl;
        }
        while (FindNextFileW(hSearch.get(), &FindData));

        if (GetLastError() != ERROR_NO_MORE_FILES)
        {
            std::wcerr << L"Error looking for next file" << std::endl;
            return -1;
        }
    }

    return 0;
}

【讨论】:

  • 我试了一下,效果很好,也更优雅。我必须更深入地学习。非常感谢现在
  • 对不起,我现在才尝试第二个示例(第一个完美运行)。除了难以理解 std::unique_ptr 似乎无法正常工作:错误 C2039: 'unique_ptr' : is not a member of 'std' error C2065: 'unique_ptr' : undeclared identifier error C2275: 'HANDLE' : 非法使用这种类型的表达我想更好地理解它是如何工作的
  • std::unique_ptr 是在 C++11 中引入的,因此请确保您使用的是支持 C++11 的编译器。一些编译器,如 gcc,要求您显式配置它们以启用 C++11,即-std=c++11。如果您不使用 C++11,我添加了另一个示例
  • 啊好的,我用的是vc++ 2008
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-26
  • 1970-01-01
相关资源
最近更新 更多