曾经有这么一个需要,就想自己实现一个。虽然我知道java内置文件操作的库而C++没有,但还是不想换语言(文人相轻,程序猿更相轻)。于是就上网找了一段C版本的代码,就是这个:

 1 #include <iostream>
 2 #include <vector>
 3 #include <string>
 4 #include <cstring>
 5 #include <io.h>
 6 using namespace std;
 7 /**
 8 *获取文件夹中所有文件名
 9     input
10         path:   文件夹路径
11         exd:    文件后缀,如为空则全选
12     output
13         files:  容器
14 */
15 void getFileName(string path, string exd, vector<string>& files)
16 {
17     /// 文件句柄
18     long hFile = 0;
19     /// 文件信息
20     struct _finddata_t fileinfo;
21     string pathName(path), exdName = "\\*."+exd;
22     if(hFile = _findfirst((pathName+exdName).c_str(), &fileinfo) != -1)
23     {
24         do
25         {///如果有文件夹,迭代之
26             if(fileinfo.attrib&_A_SUBDIR)
27             {
28                 if(strcmp(fileinfo.name,".") && strcmp(fileinfo.name,".."))
29                     getFileName(pathName+"\\"+fileinfo.name, exd, files);
30             }
31             else
32             {
33                 if(strcmp(fileinfo.name,".") && strcmp(fileinfo.name,".."))
34                     files.push_back(fileinfo.name);
35             }
36         }while(_findnext(hFile, &fileinfo)==0);
37         /**这段代码跑出来实际上只能找到一个文件就结束了,找原因还很麻烦
38         */
39         _findclose(hFile);
40     }
41 }
42 int main()
43 {
44     string path("E:");
45     vector<string> files;
46     getFileName(path,"",files);
47     for(int i = 0; i < files.size(); i++)
48         cout<<files[i]<<endl;
49     return 0;
50 }

结果调了一上午还没调过,真是坑爹。

后来发现用dos也能做,而且简单到让我想撞墙,就像这样

@echo off
dir /s/b *.txt > 文件名.txt
exit

就这么一行,dir就不用说了,/s表示递归遍历,/b表示一个文件一行,*.txt表示查找txt文件,然后写入到一个文件中。

把它保存为bat,放入当前文件夹就可了。不过它输出的是绝对路径,还得自己再加工。

问题是解决了,可是也太快了,我还没感觉呢。

后来,我试着用NB的python解决,在实现的过程中,我感觉我就是在搞翻译。比如我知道要“获取当前文件夹”,然后python里是哪个函数有这个功能呢?找。我知道要“递归遍历”,但是python里是哪个函数有这个功能呢?找。大部分时间就是在看文档,学习语法,模块,并没有什么乐趣,也许是因为我对这个语言不熟吧。最后实现了递归与非递归两个版本,如下所示:

1 import os
2 import fnmatch
3 f=open("图片.txt","w+")
4 for file in os.listdir(os.getcwd()):
5     if fnmatch.fnmatch(file, '*.jpg'):
6         f.write(file+"\n")
7     #    f.write(os.path.realpath(file)+"\n")
8 f.close()
 1 import os
 2 import fnmatch
 3 f=open("图片.txt","w+")
 4 for tup in os.walk(os.getcwd()):
 5     lst = tup[2]
 6     dirpath = tup[0]
 7     for file in lst:
 8         if fnmatch.fnmatch(file, '*.jpg'):
 9             f.write(os.path.join(dirpath, file)+"\n")
10        #     f.write(file+"\n")
11 f.close()

其中,getcwd()就是获取当前目录,listdir()是获取目录下所有子目录(非递归),walk()是递归获取,返回一个list of tuple,tuple包含三个元素,分别是当前目录,list of当前目录下的文件夹,list of当前目录下的文件。fnmatch()就是一个匹配的函数;realpath()返回绝对路径,join()连接路径。不得不说,脚本语言还是很方便的,源代码可以当exe直接运行。

后来,我遇到了吊炸天的Boost,终于又可以用C++实现了。Boost的filesystem库实现了文件操作,而且它的可读性非常好,几乎不需要解读。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <string>
 4 #include <boost/filesystem/operations.hpp>
 5 using namespace std;
 6 using namespace boost;
 7 namespace fs = boost::filesystem;
 8 using rd_iter = fs::recursive_directory_iterator;
 9 using d_iter = fs::directory_iterator;
10 int main()
11 {
12     string ext;
13     cout<<"请输入文件格式(含.)"<<endl;
14     cin>>ext;
15     ofstream fout("output.txt");
16     rd_iter pos("./"), End;
17     for(; pos != End; ++pos)
18     {
19         if(!is_directory(*pos) &&
20            pos->path().extension() == ext)
21         {   //仅文件
22         //    fout << pos->path().filename().string() << endl;
23             //绝对路径
24         //    fout << system_complete(pos->path()).string() << endl;
25             //相对路径
26             fout << pos->path().relative_path().string() << endl;
27         }
28     }
29 }

 

用"./"表示当前目录,多么简单直观。d_iter是非递归迭代器,rd_iter是递归迭代器,这里用迭代器来遍历路径。Boost把迭代器玩出魔性来了,好多用法第一次看的时候是跪着看的。更多的内容可以去看Chrono的书,这里就不说了。