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()函數執行文件的刪除操作。