4

使用 boost 的新手。使用它来加载图像集合。问题是文件夹中的图像数量将继续增长,我最终不想将它们全部添加到我的显示程序中。我在 OS X 上并使用 C++。

如何调整此示例代码以仅从目录的顶部或底部加载 30 张图像?只加载最新的文件会很棒,但我会满足于改变它。不幸的是,在我的循环中只说 (it <30) 是行不通的,因为它需要等效于 fs::directory_iterator。

示例代码:

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();
        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + photoFileName ), mipFmt) );
            cout << "Loaded: " << photoFileName <<endl;
        }
    }
}

编辑:这就是我最终这样做的方式。有点混合了这两种方法,但我需要向后排序,即使它不一定是可以预见的倒退……抓住我的机会。不是世界上最干净的东西,但我必须将他们的想法转化为我理解的 C++ 风格

    vector<string> fileList;
int count = 0;

photoboothTex.clear();//clear this out to make way for new photos

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )    {
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();

        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            fileList.push_back(photoFileName);
        }
    }
}
for (int i=(fileList.size()-1); i!=0; i--) {

        photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + fileList[i%fileList.size()] )) );
        cout << "Loaded Photobooth: " << fileList[i%fileList.size()] <<endl;
        if(++count ==40) break; //loads a maximum of 40 images
}
4

2 回答 2

5

这是一个使用 boost::filter_iteratorwithdirectory_iterator将路径存储到向量中的常规文件的工作示例。我根据 对向量进行了排序last_write_time()。为简洁起见,我还省略了错误检查 - 如果目录中的文件少于 30 个,此示例将崩溃。

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/filesystem.hpp>
#include <boost/iterator/filter_iterator.hpp>
namespace fs = boost::filesystem;

int main()
{
    fs::path p("My image directory");
    fs::directory_iterator dir_first(p), dir_last;
    std::vector<fs::path> files;

    auto pred = [](const fs::directory_entry& p)
    {
        return fs::is_regular_file(p);
    };

    std::copy(boost::make_filter_iterator(pred, dir_first, dir_last),
              boost::make_filter_iterator(pred, dir_last, dir_last),
              std::back_inserter(files)
              );

    std::sort(files.begin(), files.end(),
              [](const fs::path& p1, const fs::path& p2)
              {
                  return fs::last_write_time(p1) < fs::last_write_time(p2);
              });

    std::copy_n(files.begin(), 30, std::ostream_iterator<fs::path>(std::cout, "\n"));
}

为了使您的示例正常工作,您可以像这样构造 for 循环:

fs::path pPhoto( photobooth_texture_path );
fs::directory_iterator it( pPhoto );

for ( size_t i = 0;  i < 30 && it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // load the image
        ++i;
    }
}
于 2012-07-11T20:27:20.367 回答
3

显然你不能说it < 30因为 30 不是 directory_iterator。

而且,即使你可以,那只会计算前 30 个文件期间,而不是前 30 个非隐藏文件,我怀疑这不是你想要的(特别是因为“隐藏”的通常 *nix 规则是“开始'.'”,并且这些文件往往排在第一位)。

但是您可以轻松地自己跟踪计数:

int count = 0;

fs::path pPhoto( photobooth_texture_path );
for ( fs::directory_iterator it( pPhoto ); it != fs::directory_iterator(); ++it )
{
    if ( fs::is_regular_file( *it ) )
    {
        // -- Perhaps there is a better way to ignore hidden files
        string photoFileName = it->path().filename().string();
        if( !( photoFileName.compare( ".DS_Store" ) == 0 ) )
        {
            photoboothTex.push_back( gl::Texture( loadImage( photobooth_texture_path + photoFileName ), mipFmt) );
            cout << "Loaded: " << photoFileName <<endl;
            if (++count == 30) break;
        }
    }
}

就是这样。

只加载最新的文件会很棒,但我会满足于改变它。

这没有得到最新的 30 个,只有“一些 30 个”。boost::filesystem迭代“好像通过调用 POSIX readdir_r()”,并且readdir_r迭代一个目录流,该目录流被指定为“特定目录中所有目录条目的有序序列”,但是没有办法告诉它是什么订购你想要的那个序列。

当然,您可以通过阅读整个列表来添加自己的排序,然后根据需要进行排序。请参阅上面的 jrok 答案。但这也有一些缺点:

  • 这不是那么简单。
  • 如果你有大目录,它会慢得多(因为你必须读入,可能还有统计,所有 3000 个条目来对它们进行排序,而不是仅仅读取 30 个)。
  • 它会占用更多的内存。

最终,这是一个权衡。

虽然没有那么简单,但有人 (jrok) 已经编写了代码,无论如何理解他的代码是一次值得学习的经历。虽然它“慢得多”,但它可能仍然“足够快”。虽然它需要“更多的内存”,但它可能仍然只是杯水车薪。但是您必须评估这些因素并自己决定。

我会提到另外两件事:

首先,如果速度不是问题但内存是问题(非常不可能,但并非完全不可能),您可以通过只保留目前找到的最后 30 个文件而不是所有文件来使代码更复杂一些。(例如,将它们放在集合中而不是向量中;对于每个新值,如果它比集合中最旧的值更旧,则忽略它;否则,将其插入集合中并删除最旧的值。)

其次,如果您不关心可移植性,并且愿意从 boost::filesystem 换成一些丑陋的、特定于平台的、基于 C 的 API,那么您的平台可能有一种按排序顺序读取目录条目的方法。但是我不会追求这个,除非你真的需要排序和效率,以至于你愿意完全牺牲便携性和简单性。

于 2012-07-12T00:54:35.670 回答