我正在编写一个程序,输出它所在文件夹中所有文件的名称,如果其中两个文件具有相同的大小,则只输出一个。请注意,我是升级库的新手,而不是经验丰富的程序员。
以下是我的想法:
#include <boost/filesystem.hpp>
#include <iostream>
#include<string>
#include<cstdio>
using namespace std;
void files(string a = ".")
{
bool check = 1;
boost::filesystem::directory_iterator iterator(a);
for (; iterator != boost::filesystem::directory_iterator(); ++iterator)
{
if (is_directory(iterator->path()))
{
files(iterator->path().string());
}
else
{
boost::filesystem::directory_iterator iterator2(a);
iterator2 = iterator;
if (iterator != boost::filesystem::directory_iterator())
{
iterator2++;
}
for (; iterator2 != boost::filesystem::directory_iterator(); ++iterator2)
{
if (file_size(iterator->path()) == file_size(iterator2->path()))
{
check = 0;
}
}
}
if (check == 1)
{
cout << (iterator->path().filename()) << endl;
}
else
{
check = 1;
}
}
}
int main()
{
files();
}
我试图让它列出所有文件而没有异常,但它工作正常但是当我添加第二个for循环而第二个directory_iterator出错时。
答案 0 :(得分:0)
潜在的问题是boost::filesystem::directory_iterator
是一个输入迭代器,不能保证保持相等性:请参阅directory_iterator documentation处的注释。
在实现中,它可能正在使用类似POSIX opendir
,readdir
接口的东西,其中有一个基础打开文件描述符,从中连续读取目录条目。
因此,在分配后推进可能与iterator2
共享相同基础状态的iterator1
可能正在改变iterator1
将返回的内容。
实际上,在我的测试平台(Linux,g ++)上,iterator2
循环完成后,iterator2等于结束迭代器,iterator1
也等于结束迭代器和程序尝试访问文件名时出现段错误。
简而言之,iterator2和iterator1没有独立的状态,即使应该是这种情况并不明显。要解决此问题,最简单的方法是记录您在std::set
(或C ++ 11中的std::unordered_set
)中看到的文件大小,并且只打印路径该集合尚未包含该文件大小。
我在这里添加了一个使用std::set
来执行此操作的版本。为了简单起见,我忽略了递归下降到子目录中。您需要确定是否要省略与同一子目录中的文件大小相同的文件,或者省略任何子目录中的文件。
#include <boost/filesystem.hpp>
#include <iostream>
#include <string>
#include <set>
using namespace std;
void files(string a = ".")
{
boost::filesystem::directory_iterator iterator(a),dir_end;
std::set<uintmax_t> file_sizes;
for (; iterator != dir_end; ++iterator) {
bool emit = true;
if (!is_directory(iterator->path())) {
uintmax_t size = file_size(iterator->path());
if (file_sizes.find(size) == file_sizes.end()) {
// set does not contain this file size yet.
file_sizes.insert(size);
}
else {
// set already contains this file size, so don't print path
emit = false;
}
}
if (emit) {
cout << (iterator->path().filename()) << endl;
}
}
}
int main() {
files();
}
答案 1 :(得分:0)
我自己做了一个手指练习。
我意识到它可能过于通用/复杂而无法达到您的目的(例如,它可以优雅地处理由于例如权限问题导致文件大小失败的情况),但也许您仍然可以获得一些灵感从它:
<强> Live On Coliru 强>
#include <boost/filesystem.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <map>
#include <iostream>
#include <string>
#include <cstdio>
namespace fs = boost::filesystem;
template <
typename KeyFunc,
typename OutputUnique,
typename HandleDupe,
typename Path = boost::filesystem::path,
typename KeyType = decltype(std::declval<KeyFunc>()(Path{})),
typename Record = std::pair<boost::optional<KeyType> const, Path>
>
void files(std::string const& curdir, OutputUnique output, KeyFunc const& key, HandleDupe const& handler)
{
using namespace boost::adaptors;
using namespace boost;
using path = fs::path;
using paths = std::vector<path>;
auto safe_key = [&key](path const& p) {
optional<KeyType> sz;
try { sz = key(p); } catch(...) { }
return std::make_pair(sz, p);
};
std::function<void(path const&)> recurse = [&](path const& curdir) {
paths files;
paths dirs;
std::map<optional<KeyType>, path> seen;
try {
auto entries
= make_iterator_range(fs::directory_iterator(curdir), {})
| transformed(std::mem_fn(&fs::directory_entry::path))
;
std::partition_copy(
entries.begin(), entries.end(),
back_inserter(dirs),
back_inserter(files),
[](path const& p) { return is_directory(p); }
);
for(auto& f: files) {
auto insertion = seen.insert(safe_key(f));
if (!insertion.second && insertion.first->first)
handler(*insertion.first, safe_key(f));
else
*output++ = f;
}
boost::for_each(dirs, recurse);
} catch(std::exception const& e) {
std::cerr << "Skipping " << curdir << ": " << e.what() << "\n";
}
};
recurse(curdir);
}
template <typename OutputUnique = std::ostream_iterator<fs::path> >
void files(std::string const& curdir = ".", OutputUnique output = std::ostream_iterator<fs::path>(std::cout, "\n"))
{
using fs::path;
using Record = std::pair<boost::optional<size_t> const, path>;
files(
curdir,
output,
[](path const&p) { return file_size(p); },
[](Record const&, Record const&) { }
);
}
#include <boost/function_output_iterator.hpp>
int main() {
files("."); // prints non-dupes recursively
// advanced use: print nothing for non-dupes, but print the duplicate pairs
auto devnull = boost::make_function_output_iterator([](fs::path){});
files(".",
devnull, // back_inserter(some_vector), etc.
[](fs::path const& p){return file_size(p);}, // some other key?
[](auto const& dupe, auto const& orig) {
std::cout << "Duplicate size (" << *dupe.first << ") in " << dupe.second << "\n"
<< "\tOriginal: " << orig.second << "\n";
});
}
打印
"./main.cpp"
"./a.out"
Duplicate size (3208) in "./main.cpp"
Original: "./dupe.cpp"