如何从文件夹中获取文件名并保持文件名顺序不变?

时间:2014-08-17 12:25:10

标签: c++ vector filenames

我从文件夹中获取了文件名并将名称发送到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;
}

结果是这样的:

result

我真正想要的是订单从1到12。

1 个答案:

答案 0 :(得分:1)

  

我发现订单与文件夹中的文件订单不同。

你可能意味着它们不是自然命令的,即文件名中的数字似乎不受尊重。

这是因为 lexigraphical比较不尊重数学。 "12"小于"2" ,因为"12"已经&#34;胜出&#34;对于第一个字符,因为字符串逐字符进行比较,'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上搜索&#34;字符串自然顺序&#34;,您会发现无数的算法可供使用。

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

如果它实际上太慢或有其他问题,请随意拿走这件事并改进它。它的意图比生产代码中的使用更具教育意义:

#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