从文件夹中读取文件并将其保存到字符串向量中

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

本文关键字:保存 字符串 向量 文件夹 读取 文件      更新时间:2023-10-16

我正在尝试从文件夹中读取文本文件,并将名称保存到字符串向量中。这是我的代码。我可以编译并运行它,但它不会将我的文件保存到向量中。

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;
}
}

我们非常感谢您提供的任何帮助。

一个问题是:

FindFileData.cFileName=="*.txt"

首先,这不会比较字符串。它比较指针值。如果要比较字符串,请使用_tcscmp:

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

其次,这是错误的:

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

您正试图将非宽字符串强制转换为宽字符串或非宽字符串,这取决于项目的字符集构建类型(我假设您使用的是Visual Studio,但它与您的C++工具有关)。

底线是never强制转换字符串类型以适应参数类型。铸造字符串是而不是将字符串从一种类型转换为另一种类型。您应该编写从不需要强制转换字符串的代码——如果最终强制转换字符串,那么代码就是错误的。

如果删除强制转换,你总是可以判断出有什么不好或需要仔细检查,通过删除强制转换编译器会抛出一个错误,告诉你类型不匹配(这不仅适用于字符串,也适用于你认为需要强制转换的任何类型)。

对于此实例,修复方法是使用tchar.h中定义的_TTEXT宏,该宏为您提供适当的字符串文字类型。

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

最后,您真的将文件名与"*.txt"进行比较吗?Windows系统中的任何文件都不能用星号命名。

您的代码有很多问题。TCHAR数据处理不正确。FindFirstFile数据的循环不正确(您正在跳过找到的第一个文件)。文件扩展名的比较无效。

请尝试类似的方法,特别是因为您使用的是std::stringstd::cout,这意味着您也使用了基于ANSI的Win32 API(否则您显示的代码将无法编译):

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;
}

否则,您应该切换到std::wstringstd::wcout,以及基于Unicode的API:

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;
}

无论出于何种原因,如果您必须坚持使用TCHAR数据,您也可以这样做:

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;
}

我认为问题的主要原因是这行代码

Dataset.name.push_back(FindFileData.cFileName);

在这一行中,您将WIN32_FIND_DATA::cFileName属性直接推回到vector,并且由于vector在下次调用FindNextFile时保留该属性的地址,它将覆盖以前的值。出于这个原因,最好分配新的缓冲区并将WIN32_FIND_DATA::cFileName复制到这个新缓冲区,然后将这个新缓冲推送到向量。