当前位置: 动力学知识库 > 问答 > 编程问答 >

c++ - Read files from a folder and save it to vector of strings

问题描述:

I am trying to read textfiles from an folder and save the names to a vector of strings. This is my code by now. I can compile and run it, but it is not saving my files to the vector.

int main(){

Data Dataset;

WIN32_FIND_DATA FindFileData;

HANDLE hFind;

// Find the first file in the directory.

hFind = FindFirstFile(LPCTSTR("C:\\Users\\bla\\Desktop\\c++\\data\\*"), &FindFileData);

if (hFind == INVALID_HANDLE_VALUE) {

cout<<"ERROR"<<endl;

}

else{

while (FindNextFile(hFind, &FindFileData) != 0) {

if(FindFileData.cFileName=="*.txt")

{

Dataset.name.push_back(FindFileData.cFileName);

}

cout<<FindFileData.cFileName<<endl;

}

FindClose(hFind);

}

for(int i=0; i<Dataset.name.size(); i++){

cout<<Dataset.name[i]<<endl;

}

}

Any assistance that can be offered is greatly appreciated.

网友答案:

One issue is this:

FindFileData.cFileName=="*.txt"

First, this does not compare strings. It compares pointer values. If you want to compare strings, then use _tcscmp:

if ( _tcscmp(FindFileData.cFileName, _T("*.txt")) == 0 )

Second, this is wrong:

hFind = FindFirstFile(LPCTSTR("C:\\Users\\bla\\Desktop\\c++\\data\\*"), &FindFileData);

You are attempting to cast a non-wide string into one that may be wide, or may not be wide, depending on the character set build type for your project (I'm assuming you're using Visual Studio, but it is relevant to whatever your C++ tools happen to be).

The bottom line is to never cast string types to fit the parameter type. Casting a string is not converting the string from one type to another. You should write code that never needs to cast strings -- if you wind up casting strings, the code is wrong.

You can always tell something is bad or needs to be looked at very closely if you remove the cast, and by removing the cast the compiler throws an error telling you that the types don't match (this not only goes for strings, but any type you feel you need to cast).

For this instance, the fix is to use the _T or TEXT macro defined in tchar.h that gives you the appropriate string literal type.

hFind = FindFirstFile(_T("C:\\Users\\bla\\Desktop\\c++\\data\\*"), &FindFileData);

Last, are you really comparing a file name with "*.txt"? No file in the Windows system can be named with an asterisk.

网友答案:

There are many problems with your code. Incorrect handling of TCHAR data. Incorrect looping of the FindFirstFile data (you are skipping the first file found). Invalid comparison of the file extensions.

Try something more like this instead, especially since you are using std::string and std::cout, which means you are also using ANSI-based Win32 APIs (otherwise the code you showed would not compile):

struct Data
{
    std::vector<std::string> name;
    unsigned int vehicle;
    unsigned int dim;
    int maxQ;
};

int main()
{
    Data Dataset;
    WIN32_FIND_DATAA FindFileData;
    HANDLE hFind;
    DWORD dwErr;

    // Find the first file in the directory.
    hFind = FindFirstFileA("C:\\Users\\bla\\Desktop\\c++\\data\\*.txt", &FindFileData);

    if (hFind == INVALID_HANDLE_VALUE)
    {
        dwErr = GetLastError();
        if (dwErr != ERROR_FILE_NOT_FOUND)
            std::cerr << "ERROR: " << dwErr << std::endl;
    } 
    else
    {
        do
        {
            if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
            {
                Dataset.name.push_back(FindFileData.cFileName);
                //std::cout << FindFileData.cFileName << std::endl;
            }
        }
        while (FindNextFileA(hFind, &FindFileData));

        dwErr = GetLastError();
        if (dwErr != ERROR_NO_MORE_FILES)
            std::cerr << "ERROR: " << dwErr << std::endl;

        FindClose(hFind);
    }

    for(int i = 0; i < Dataset.name.size(); i++)
    {
        std::cout << Dataset.name[i] << std::endl;
    }

    return 0;
}

Otherwise, you should switch to std::wstring and std::wcout, and Unicode-based APIs:

struct Data
{
    std::vector<std::wstring> name;
    unsigned int vehicle;
    unsigned int dim;
    int maxQ;
};

int main()
{
    Data Dataset;
    WIN32_FIND_DATAW FindFileData;
    HANDLE hFind;
    DWORD dwErr;

    // Find the first file in the directory.
    hFind = FindFirstFileW(L"C:\\Users\\bla\\Desktop\\c++\\data\\*.txt", &FindFileData);

    if (hFind == INVALID_HANDLE_VALUE)
    {
        dwErr = GetLastError();
        if (dwErr != ERROR_FILE_NOT_FOUND)
            std::wcerr << L"ERROR: " << dwErr << std::endl;
    } 
    else
    {
        do
        {
            if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
            {
                Dataset.name.push_back(FindFileData.cFileName);
                //std::wcout << FindFileData.cFileName << std::endl;
            }
        }
        while (FindNextFileW(hFind, &FindFileData));

        dwErr = GetLastError();
        if (dwErr != ERROR_NO_MORE_FILES)
            std::wcerr << L"ERROR: " << dwErr << std::endl;

        FindClose(hFind);
    }

    for(int i = 0; i < Dataset.name.size(); i++)
    {
        std::wcout << Dataset.name[i] << std::endl;
    }

    return 0;
}

If you have to stick with TCHAR data for whatever reason, you can alternatively do something like this instead:

typedef std::basic_string<TCHAR> tstring;

struct Data
{
    std::vector<tstring> name;
    unsigned int vehicle;
    unsigned int dim;
    int maxQ;
};

int main()
{
    Data Dataset;
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind;
    DWORD dwErr;

    #ifdef UNICODE
    std::wostream &std_out = std::wcout;
    std::wostream &std_err = std::wcerr;
    #else
    std::ostream &std_out = std::cout;
    std::ostream &std_err = std::cerr;

    // Find the first file in the directory.
    hFind = FindFirstFile(TEXT("C:\\Users\\bla\\Desktop\\c++\\data\\*.txt"), &FindFileData);

    if (hFind == INVALID_HANDLE_VALUE)
    {
        dwErr = GetLastError();
        if (dwErr != ERROR_FILE_NOT_FOUND)
            std_err << TEXT("ERROR: ") << dwErr << std::endl;
    } 
    else
    {
        do
        {
            if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
            {
                Dataset.name.push_back(FindFileData.cFileName);
                //std_out << FindFileData.cFileName << std::endl;
            }
        }
        while (FindNextFile(hFind, &FindFileData));

        dwErr = GetLastError();
        if (dwErr != ERROR_NO_MORE_FILES)
            std_err << TEXT("ERROR: ") << dwErr << std::endl;

        FindClose(hFind);
    }

    for(int i = 0; i < Dataset.name.size(); i++)
    {
        std_out << Dataset.name[i] << std::endl;
    }

    return 0;
}
网友答案:

I think the main cause of problem is in this line of code

Dataset.name.push_back(FindFileData.cFileName);

In this line you push back WIN32_FIND_DATA::cFileName property directly to vector and because vector hold address of this property next time you call FindNextFile it will override previous value. For this reason it is better to allocate new buffer and copy WIN32_FIND_DATA::cFileName to this new buffer and then push this new buffer to vector.

分享给朋友:
您可能感兴趣的文章:
随机阅读: