文件的命名是这样的,依次排列,我们的目标是将其修改为1.pcd,2.pcd …,以下使用C++完成任务,以及记录下在这过程遇到的错误,参考的网址放在最下面
1.读取某个文件夹下面所有“.xxx”格式的文件,读取的函数在io.h中,用到的函数有这就要靠_findfirst、_findnext和_fineclose,接下来先来讲下这三个函数的作用
_findfirst函数原型为:long _findfirst( char *filespec, struct _finddata_t *fileinfo );
findfirst功能:搜索与指定的文件名称匹配的第一个实例,若成功则返回第一个实例的句柄,否则返回-1L。
filespec:标明文件的字符串,可支持通配符。比如:*.c,则表示当前文件夹下的所有后缀为C的文件。
fileinfo :这里就是用来存放文件信息的结构体的指针。这个结构体必须在调用此函数前声明,不过不用初始化,只要分配了内存空间就可以了。函数成功后,函数会把找到的文件的信息放入这个结构体中。
_findnext的函数原型是: int _findnext( long handle, struct _finddata_t *fileinfo );
findnext功能:搜索与findfirst函数提供的文件名称匹配的下一个实例,若成功则返回0,否则返回-1
handle:即由_findfirst函数返回回来的句柄。
fileinfo:文件信息结构体的指针。找到文件后,函数将该文件信息放入此结构体中。
_findclose的函数原型是int _findclose( long handle );
_findclose的功能是关闭指定的搜索句柄并释放相关资源,成功返回0,失败返回-1
handle :_findfirst函数返回回来的句柄。
//文件的路径,也可以使用cin自己指定,例如cin>>path
char * filePath = "D:\\sample";
void getFiles( string path, vector& files )
{
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) != -1)
{
do
{
//如果是目录,迭代之
//如果不是,加入列表
if((fileinfo.attrib & _A_SUBDIR))
{
if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0)
getFiles( p.assign(path).append("\\").append(fileinfo.name), files );
}
else
{
//如果是文件的化,放进来,这个加了路径名的path的命名
files.push_back(p.assign(path).append("\\").append(fileinfo.name) );
}
}while(_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
int main() {
string file_path;
cout << "请输入文件夹的名字:";
cin >> file_path;
vector files;
getFiles(file_path, files);
int size = files.size();
cout << "file size is :" << size << endl;
cout << "----------------------" << endl;
for (int i = 0; i < size; i++) {
cout << files[i]<< endl;
}
}
直接这样用的话,会出现这种情况,就是读取的顺序发生了变化,比如上面的图第一个文件时2973157.pcd,但是现在已经发生了变化,如果我直接修改名字的话,那么重命名的文件0.pcd 对应着是1002980999.pcd ,而不是2973157.pcd ,产生这个的原因是由于window下读取文件是按 字符串比较的顺序进行排列的 ,字符串“22”比“1000”大。所以我们需要对排序进行调整,也就是使用比较器。
我们的目标是:
1.首先我们对刚才的getFiles函数进行一个小修改
//files.push_back(p.assign(path).append("\\").append(fileinfo.name) );
files.push_back(fileinfo.name);//不包含路径,只包含文件名
2.接着我们写一个C++比较器,然后再利用sort函数便可以实现排序了。
//比较器的思路是先将字符串转化为数字,然后对数字进行比较
bool comparator(const string& src1, const string& src2) {
string find_src = ".pcd";//
int num1 = stoi(src1.substr(0, src1.find(find_src)));//关于字符串的使用可以查看末尾的链接
int num2 = stoi(src2.substr(0, src2.find(find_src)));//stoi是将字符转数字,
if (num1 > num2) {
return 0;
}
else
{
return 1;//return 1 实现从小到大
}
}
//接着我们main函数打印之前sort一下
vector files;
getFiles(file_path, files);
sort(files.begin(), files.end(), comparator);
for (int i = 0; i < size; i++) {
cout << files[i]<< endl;
}
由于是新手,不知道啥原因,开始上网搜各种帖子,还是没能解决,开始单步调试大法,一直运行感觉也没问题,然后突然想到文件的末尾是
这已经超出了int 类型了,所以比较器那里用int来接肯定不行,于是想到了修改比较器,由于自动转型c++中只有提供到stoi,而我们需要long long int ,所以再多些一个函数
long long int f(const string& str) {
long long int res = 0;
for (int i = 0; i < str.size(); i++)
{
res = res * 10 + str[i] - '0';
}
return res;
}
bool comparator(const string& src1, const string& src2) {
string find_src = ".pcd";
long long int num1 = f(src1.substr(0, src1.find(find_src)));
long long int num2 = f(src2.substr(0, src2.find(find_src)));
if (num1 > num2) {
return 0;
}
else
{
return 1;
}
}
修改完这个比较器后,就可以实现按顺序进行打印了,接下来我们要对这个排好序的文件进行重命名,以便我在Linux下对这些文件进行顺序读取,这些文件其实是点云文件,本来就是按时间顺序进行排序的。
这里会使用到rename函数,下文也有链接,大家可以自己看下简单的示例,然后我们对他进行稍微的修改
int rename( const char *oldname, const char *newname );
The rename()
function takes a two arguments: oldname, newname and returns an integer value. It renames the file represented by the string pointed to by oldname to the string pointed to by newname.
string path = "C:\\Users\\zhuang\\Desktop\\dataset\\";
for (int i = 0; i < size; i++) {
if (rename((path + files[i]).c_str(), (path + to_string(i)).c_str()) != 0) {
perror("Error renaming file");
}
else {
cout << "File renamed successfully";
}
}
//rename((path + files[i]).c_str(), (path + to_string(i)).c_str())这个语句是找到我们文件夹下的文件并进行命名修改
//注意一点就是今天3/28给蠢了自己一下,想把生成的文件放进一个新的目录中,使用rename((file_path + files[i]).c_str(), (path + to_string(i)).c_str()),
//rename指令只是修改文件的名字,并不能实现文件的拷贝!
总结:
应该要对ROS上面采集的雷达数据格式进行修改,毕竟现在只采集了几分钟,数据文件的命名就变成这样子,要是再大点,long long int 也装不下了.
参考的文章:
微软c++官方文档https://docs.microsoft.com/en-us/cpp/c-runtime-library/filename-search-functions?view=vs-2017
文件读取https://www.cnblogs.com/fnlingnzb-learner/p/6424563.html
rename 函数https://www.programiz.com/cpp-programming/library-function/cstdio/rename
类型转换https://blog.csdn.net/HiccupHiccup/article/details/62421032
c++字符串截取,替换,查找函数 https://blog.csdn.net/ezhou_liukai/article/details/13779091
批量修改名字https://blog.csdn.net/tom555cat/article/details/17389247
rename 的用法https://stackoverflow.com/questions/37229205/use-of-atoi-function-in-c