【问题标题】:how to get filenames from a folder and keep filenames order unchanged?如何从文件夹中获取文件名并保持文件名顺序不变?
【发布时间】:2014-08-17 12:25:09
【问题描述】:

我从文件夹中获取文件名并将名称发送到vector<string>,但是当我打印vector<string> 时,我发现顺序与文件夹中的文件顺序不同。 我的代码如下所示:

#include <windows.h>
#include <iostream>
#include <vector>

using namespace std;

void searchFileInDirectroy( const string& dir, vector<string>& outList );

void searchFileInDirectroy( const string& dir, vector<string>& outList )
{
        WIN32_FIND_DATA findData;
        HANDLE hHandle;
        string filePathName;
        string fullPathName;

        filePathName = dir;
        filePathName += "\\*.*";

        hHandle = FindFirstFile( filePathName.c_str(), &findData );
        if( INVALID_HANDLE_VALUE == hHandle )
        {
                cout<<"Error"<<endl;
                return ;
        }

        do
        {
                if( strcmp(".", findData.cFileName) == 0 || strcmp("..", findData.cFileName) == 0 )
                {
                        continue;
                }

                fullPathName = dir;
                fullPathName += "\\";
                fullPathName += findData.cFileName;

                if( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
                {
                        searchFileInDirectroy( fullPathName, outList );
                }
                else
                {
                        outList.push_back(fullPathName);
                }

        } while( FindNextFile( hHandle, &findData ) );

        FindClose( hHandle );
}

int main()
{
    ///get filenames from folder;
    vector<string> pathList;
    searchFileInDirectroy("D:/OpenCV/calculate laef area--cui.ver2.0/source", pathList);

    for(unsigned int i=0;i<pathList.size();i++)
    {
        cout<<pathList[i]<<endl;
    }
return 0;
}

结果是这样的:

我真正想要的是顺序是从 1 到 12。

【问题讨论】:

  • 文件夹中的文件没有固有的顺序。
  • 您必须对向量进行排序,因为 FindFile 使用文件系统的顺序。
  • 对于(逻辑)排序,您可能需要msdn.microsoft.com/library/windows/desktop/…
  • @MrTux 感谢您的回复。你能给我举个例子吗?我试过 FindFile 方法,但没有成功。
  • @just_rookie:我仍然不清楚您是否需要自然排序(即您不喜欢“12”在“2”之前的事实)或本机低级文件系统顺序。

标签: c++ vector filenames


【解决方案1】:

我发现顺序和文件夹中文件的顺序不一样。

您可能是说它们不是自然排序的,即文件名中的数字似乎不受尊重。

这是因为词法比较不尊重数学。 "12" 小于 "2",因为 "12" 已经“胜出”第一个字符,因为字符串是逐个字符比较的,'1' 小于 '2'

因此,您首先需要一种用于自然排序的算法。 C++ 没有提供,但它提供了一种使用std::sort 对具有任何给定排序关系的范围进行排序的方法:

#include <algorithm>

// ...

struct NaturalOrdering
{
    bool operator()(std::string const &lhs, std::string const &rhs) const
    {
        // ...
    }
};

// ...

vector<string> pathList;

// ...

std::sort(pathList.begin(), pathList.end(), NaturalOrdering());

因此,目标变成了找到一种算法,该算法定义了两者之间的自然小于关系。如果您想涵盖每一个角落案例,这不是一项微不足道的任务。如果您在 Google 上搜索“字符串自然顺序”,您会发现无数算法可供使用。

这是一个快速自制的。它的想法是将字符串分成标记,每个标记只包含数字(如“123”)或根本不包含数字(如“文件”)。然后单独比较令牌。如果两者都是数字,则将它们转换为整数并进行数学比较,否则按字典顺序进行比较。

如果它实际上太慢或有其他问题,请随时接受并改进它。其目的比在生产代码中的使用更具教育意义:

#include <iostream>
#include <string>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <sstream>

struct Token
{
    bool is_number;
    std::string string;
};

std::vector<Token> Tokenize(std::string const &input)
{
    std::string const digits = "0123456789";
    std::vector<Token> result;

    if (!input.empty())
    {
        bool inside_number_token = isdigit(static_cast<unsigned char>(input[0])) != 0;
        std::string::size_type start_current_token = 0;
        std::string::size_type start_next_token = 0;
        do
        {
            if (inside_number_token)
            {
                start_next_token = input.find_first_not_of(digits, start_current_token);
            }
            else
            {
                start_next_token = input.find_first_of(digits, start_current_token);
            }
            std::string const string = input.substr(start_current_token, start_next_token - start_current_token);
            Token token;
            token.is_number = inside_number_token;
            token.string = string;
            result.push_back(token);
            start_current_token = start_next_token;
            inside_number_token = !inside_number_token;
        }
        while (start_current_token != std::string::npos);
    }

    return result;
}

int ToInteger(std::string const &number_as_string)
{
    std::istringstream converter(number_as_string);
    int integer = 0;
    converter >> integer;
    return integer;
}

struct NaturalOrder
{
    bool operator()(std::string const &lhs, std::string const &rhs) const
    {
        std::vector<Token> const tokens_lhs = Tokenize(lhs);
        std::vector<Token> const tokens_rhs = Tokenize(rhs);

        for (std::vector<Token>::size_type index = 0; index < tokens_lhs.size() && index < tokens_rhs.size(); ++index)
        {
            Token const &token_lhs = tokens_lhs[index];
            Token const &token_rhs = tokens_rhs[index];

            if (token_lhs.is_number && token_rhs.is_number)
            {
                int const number_lhs = ToInteger(token_lhs.string);
                int const number_rhs = ToInteger(token_rhs.string);
                if (number_lhs != number_rhs)
                {
                    return number_lhs < number_rhs;
                }
            }
            else
            {
                if (token_lhs.string != token_rhs.string)
                {
                    return token_lhs.string < token_rhs.string;
                }
            }
        }
        return false;
    }
};

int main()
{
    std::vector<std::string> filenames;
    filenames.push_back("file-10.txt");
    filenames.push_back("file-2.txt");
    filenames.push_back("file.txt");
    filenames.push_back("100.txt");
    filenames.push_back("100.txt");
    filenames.push_back("file-23.txt");
    filenames.push_back("file-11.txt");
    filenames.push_back("test-01-a.txt");
    filenames.push_back("test-022-b.txt");
    filenames.push_back("test-03-c.txt");
    filenames.push_back("aaa-10-2");
    filenames.push_back("aaa-10-1");

    std::sort(filenames.begin(), filenames.end(), NaturalOrder());

    for (std::vector<std::string>::const_iterator iter = filenames.begin(); iter != filenames.end(); ++iter)
    {
        std::cout << *iter << "\n";
    }
}

输出:

100.txt
100.txt
aaa-10-1
aaa-10-2
file-2.txt
file-10.txt
file-11.txt
file-23.txt
file.txt
test-01-a.txt
test-03-c.txt
test-022-b.txt

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    相关资源
    最近更新 更多