Linux环境下用C++删除指定文件

”Talk is cheap, show me the code!“

#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <dirent.h>
#include <time.h>
using namespace std;

const long day = 86400;

//获取文件的给更新时间
long get_file_modify_time(string filepath)
{
    struct stat filehand;
    FILE *fp;
    fp = fopen(filepath.c_str(), "r");
    int fileid = fileno(fp);
    fstat(fileid, &filehand);
    fclose(fp);
    return filehand.st_mtime;
}
//获取文件夹中的所有文件
void get_files(const string dirname, vector<string> &filelist)
{
    if(dirname.empty())
        return;
    struct stat s;
    stat(dirname.c_str(), &s);
    if(!S_ISDIR(s.st_mode))
        return;
    DIR *dirhand = opendir(dirname.c_str());
    if(NULL == dirhand){
        exit(EXIT_FAILURE);
    }
    dirent *fp = nullptr;
    while((fp = readdir(dirhand)) != nullptr){
        if(fp->d_name[0] != '.'){//十分重要的一行(?)
            string filename = dirname + "/" + string(fp->d_name);
            struct stat filemod;
            stat(filename.c_str(), &filemod);
            if(S_ISDIR(filemod.st_mode)){
                get_files(filename, filelist);
            }
            else if(S_ISREG(filemod.st_mode)){
                filelist.push_back(filename);
            }
        }
    }
    closedir(dirhand);
    return;
}

bool delete_file(string filepath)
{
    return remove(filepath.c_str());
}

bool date_from_now(long now, long modify)
{
    int dis = int((1.0 * (now - modify) / day + 0.5));
    return dis >= 9;//删除最近更新时间距今超过14天的文件
}

int main()
{
    time_t now;
    time(&now);//获取当前系统时间
    string dir = "/file/cpp";//需要处理的文件夹
    vector<string> filelist;
    get_files(dir, filelist);//获取文件夹中的所有文件
    for(auto i : filelist){
        if(date_from_now(now, get_file_modify_time(i))){
            cout << i << endl;
            if(!delete_file(i)){
                cout << "The file named : " << i << " has been deleted." << endl;
            }
            else{
                cout << "Delete Failed!" << endl;
            }
        }
    }
    return 0;
}

如果没有详细学习过linux下编程,可能看不太懂这些代码,接下来详细分析:

获取文件最后更新时间

对应代码

//获取文件的给更新时间
long get_file_modify_time(string filepath)
{
    struct stat filehand;
    FILE *fp;
    fp = fopen(filepath.c_str(), "r");
    int fileid = fileno(fp);
    fstat(fileid, &filehand);
    fclose(fp);
    return filehand.st_mtime;
}

代码中用到了stat数据结构和文件操作,学过c的同学应该对文件操作都比较熟悉。

struct stat是一种保存文件信息的数据结构,使用这个结构体和一些相应的函数,需要包含

<sys/types.h>和<sys/stat.h>

对于一个文件我们可以用fstat函数来获取这个文件所对应的数据结构,fstat(int fid, struct stat *struct_stat)

其中fid为文件的描述符,可以理解为文件的一个唯一编号,获取这个编号我们就要用到文件操作函数。

首先用fopen()打开文件并获取文件指针,之后用fileno()获取文件的描述符。

对于struct stat中的属性包括:

struct stat {
        mode_t     st_mode;       //文件对应的模式,文件,目录等
        ino_t      st_ino;       //inode节点号
        dev_t      st_dev;        //设备号码
        dev_t      st_rdev;       //特殊设备号码
        nlink_t    st_nlink;      //文件的连接数
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者对应的组
        off_t      st_size;       //普通文件,对应的文件字节数
        time_t     st_atime;      //文件最后被访问的时间
        time_t     st_mtime;      //文件内容最后被修改的时间
        time_t     st_ctime;      //文件状态改变时间
        blksize_t st_blksize;    //文件内容对应的块大小
        blkcnt_t   st_blocks;     //伟建内容对应的块数量
};

我们需要获取的是文件的最近更新时间,也就是st_mtime(注意:这个属性所表示的时间是距离1970年1月1日0点0分0秒[国际标准时间]的秒数)。

获取所有的文件

对应代码

//获取文件夹中的所有文件
void get_files(const string dirname, vector<string> &filelist)
{
    if(dirname.empty())
        return;
    struct stat s;
    stat(dirname.c_str(), &s);
    if(!S_ISDIR(s.st_mode))
        return;
    DIR *dirhand = opendir(dirname.c_str());
    if(NULL == dirhand){
        exit(EXIT_FAILURE);
    }
    dirent *fp = nullptr;
    while((fp = readdir(dirhand)) != nullptr){
        if(fp->d_name[0] != '.'){//十分重要的一行
            string filename = dirname + "/" + string(fp->d_name);
            struct stat filemod;
            stat(filename.c_str(), &filemod);
            if(S_ISDIR(filemod.st_mode)){
                get_files(filename, filelist);
            }
            else if(S_ISREG(filemod.st_mode)){
                filelist.push_back(filename);
            }
        }
    }
    closedir(dirhand);
    return;
}

在这部分中我们要用到关于文件夹处理的一些函数和结构体,需要引入<dirent.h>头文件

在这部分中,首先我们要为函数传入两个参数,需要处理的文件所在的文件夹,和一个文件列表(用来保存所有文件的信息,这里用vector实现)

首先我们先将文件夹保存为struct stat变量,然后借助S_ISDIR()函数来判断这是否是一个文件夹,如果不是则退出,如果是,我们要使用DIR结构体来保存文件夹的信息。

DIR可以定义一个文件夹结构体变量,其值由opendir(char *file_path)函数获得。

之后用dirent变量可以遍历文件夹中的所有文件,包括文件夹在内。dirent变量的值由readdir(DIR *p)函数获得。

dirent结构体中保存的属性有:

struct dirent
{
   long d_ino; /* inode number 索引节点号 */
   off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
   unsigned short d_reclen; /* length of this d_name 文件名长 */
   unsigned char d_type; /* the type of d_name 文件类型 */
   char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */
}

这里我们需要用到d_name字符串来获取文件名并组成文件路径,需要注意的是:在一个文件夹中最开始的两个目录是”.“文件和".."文件,这个用vim打印文件树的时候可以看到,这两个分别代表当前目录和父目录,所以我们要在遍历时排除这两个文件,否则会产生无限递归,程序崩溃!!!

除了S_ISDIR()函数我们还会用到S_ISREG()函数,是为了判断文件是否为普通文件。

获取系统当前时间

    time_t now;
    time(&now);//获取当前系统时间

这里用到time()函数,需要包含<time.h>库

删除文件

bool delete_file(string filepath)
{
    return remove(filepath.c_str());
}

c++可以使用remove()函数执行文件的删除操作。