操纵wchar的麻烦

时间:2018-04-02 21:34:33

标签: c++ string path wchar-t

我是c ++的新手。我试图在dir中列出文件。我使用的是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 \文件1

C:\ DIR1 \ DIR2 \ file2的

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

1 个答案:

答案 0 :(得分:1)

您的代码存在一些问题。

  • 您将"\\*"连接到argv[1]指向的内存,这是不好的。您需要将pathwchar_t*指针更改为wchar_t[]数组,然后将wcscpy argv[1]数据更改为{。

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

  • *path值组合在一起时,您也不会忽略连结的cFileNames

  • 您根本不需要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;
}