任务
我们知道SLAM是处理序列图像的,有时候需要格式化的图像名字用作输入。前面提到的TUM的RGB-D数据集中图像是根据时间命名的,请从下面链接下载数据集fr1/desk
https://vision.in.tum.de/data/datasets/rgbd-dataset/download#
并解压。请编程实现将文件夹/rgb下以时间命名的序列图片重新命名为0000-9999的格式。
题目来源:从零开始一起学习SLAM | 学习SLAM到底需要学什么?-计算机视觉life
Linux下C++实现文件批量重命名
获取所有文件名findFileNames
void findFileNames(string path,vector<string>&fileNames)
{
//结构体,存放目录有关信息
DIR *pDir;
//存放读取目录后的内容
struct dirent*ptr;
if((pDir=opendir(path.c_str()))==0)
{
cout<<path<<" doesn't exists"<<endl;
}
string fileName,newPath;
while((ptr=readdir(pDir))!=0)
{
fileName=ptr->d_name;
newPath=path+"/"+ptr->d_name;
//去除当前目录.和上级目录..
if(strcmp(fileName.c_str(),".")!=0&&strcmp(fileName.c_str(),".."))
{
//cout<<newPath<<endl;//打印新的路径
fileNames.push_back(fileName);//newPath);//将新文件名存储
/*
//判断新的路径是否为目录,若是,则可递归调用函数进行子目录文件的寻找
if(opendir(newPath.c_str())!=0)
{
findFileNames(newPath,fileNames);
}
*/
}
}
}
- 虽然给出DIR为__dirstream的别名,但在本地的头文件中寻找不到后者的定义,是不透明的数据类型.
dirent结构体: 首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针(摘自《UNIX环境高级编程(第二版)》)。1 - 当使用readdir(pDir)时,pDir中指向文件指针后移,通过rewinddir(pDir)可以复位.3
- c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同.(其实它指向的是string对象内部真正的char缓冲区),所以返回const,以防止用户的修改。
这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。2
对于strcmp()函数,需要const char*类型的输入,因此可以通过c_str()将string类型变量得到该类型内容 - 此外,可以通过递归访问一个路径下包括子目录在内的所有文件,如注释所示.
批量重命名bulkRename
由于题目要求修改的数字需要补零,因此封装函数fillNum()完成工作.5
string fillNum(string str,int width,const char ch)
{
string res;
stringstream inter;
inter<<std::setw(width)<<std::setfill(ch)<<str;
inter>>res;
return res;
}
‘setw’ is not a member of ‘std’
需要引入头文件iomanip
#include<iomanip>
void bulkRename(string path,vector<string>&fileNames)
{
//声明迭代器
vector<string>::iterator iNames;
int cnt=0;
string oldPath,newPath;
for ( iNames = fileNames.begin(); iNames!=fileNames.end(); iNames++)
{
oldPath=path+"/"+*iNames;
newPath=path+"/"+fillNum(to_string(cnt),4,'0');
cout<<oldPath<<"->"<<newPath<<endl;
rename(oldPath.c_str(),newPath.c_str());
cnt++;
}
}
效果展示

完整代码
#include<iostream>
#include<vector>
#include<cstring>
#include<dirent.h>
#include<algorithm>
#include<cstdlib>
#include<iomanip>
using namespace std;
string fillNum(string str,int width,const char ch)
{
string res;
stringstream inter;
inter<<std::setw(width)<<std::setfill(ch)<<str;
inter>>res;
return res;
}
void findFileNames(string path,vector<string>&fileNames)
{
//结构体,存放目录有关信息
DIR *pDir;
//存放读取目录后的内容
struct dirent*ptr;
if((pDir=opendir(path.c_str()))==0)
{
cout<<path<<" doesn't exists"<<endl;
}
/*
if((ptr=readdir(pDir))!=0)
{
cout<<ptr->d_name<<endl;
}
rewinddir(pDir);
*/
string fileName,newPath;
while((ptr=readdir(pDir))!=0)
{
fileName=ptr->d_name;
newPath=path+"/"+ptr->d_name;
if(strcmp(fileName.c_str(),".")!=0&&strcmp(fileName.c_str(),".."))
{
//cout<<newPath<<endl;//打印新的路径
fileNames.push_back(fileName);//newPath);//将新路径加入存储
//cout<<ptr->d_name<<endl;
//判断新的路径是否为目录,若是,则可递归调用函数进行子目录文件的寻找
if(opendir(newPath.c_str())!=0)
{
findFileNames(newPath,fileNames);
}
}
}
}
void display(vector<string>&fileNames)
{
//声明迭代器
vector<string>::iterator iNames;
for ( iNames = fileNames.begin(); iNames!=fileNames.end(); iNames++)
{
/* code */
cout<<*iNames<<endl;
}
}
void bulkRename(string path,vector<string>&fileNames)
{
//声明迭代器
vector<string>::iterator iNames;
int cnt=0;
string oldPath,newPath;
for ( iNames = fileNames.begin(); iNames!=fileNames.end(); iNames++)
{
/* code */
//cout<<*iNames<<endl;
oldPath=path+"/"+*iNames;
newPath=path+"/"+fillNum(to_string(cnt),4,'0')+".png";
cout<<oldPath<<"->"<<newPath<<endl;
rename(oldPath.c_str(),newPath.c_str());
cnt++;
}
}
int main(void)
{
//读取文件路径
string path="/home/lazy/Desktop/slamStudy/code/lesson1/rgbd_dataset_freiburg1_desk/rgb";
//path="/home/lazy/test";
//存放所有文件名称
vector<string> fileNames;
//将找到的文件名存储
findFileNames(path,fileNames);
//打印排序之前
display(fileNames);
//将文件名进行排序,按次序重命名
sort(fileNames.begin(),fileNames.end());//,cmp);
//打印排序之后
cout<<"**********after sort*************\n";
display(fileNames);
//按排序顺序重新修改文件名为编号
bulkRename(path,fileNames);
//将找到的文件名存储
findFileNames(path,fileNames);
//打印修改文件名称之后
display(fileNames);
return 0;
}
参考
- [4] C++修改文件名
- [5] 字符串前面自动补零?
- [6] C++ 中vector的使用方法