Linux C 實現文件複製、文件及文件夾刪除功能

Linux下的文件操作其實是個很普通的小功能,Linux C提供了一些系統函數可以調用,我們使用的時候只需按照自己的需要封裝一下即可。

1. 文件複製

實現文件從一個目錄複製到另外一個目錄,以下是最簡單的操作,正式的工程中爲了嚴謹起見,儘量加上錯誤檢查。

#include <stdio.h>
#include <stdlib.h>
//#include <string.h>
#include <unistd.h>

#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
char buff[1024];
int len;
const int BUF_LEN = 1024;

int file_copy(const char *src_file, const char *dest_file)
{
	int fd_src, fd_dest;
 
	/* 打開源文件與目標文件 */
	fd_src = open(src_file, O_RDWR | O_CREAT);
	fd_dest = open(dest_file, O_RDWR | O_CREAT);
	
	/* 循環讀取源文件並寫入目標文件 */
	while(len = read(fd_src, buff, BUF_LEN))
	{
		write(fd_dest, buff, len);
	}
	
	/* 關閉文件句柄 */
	close(fd_src);
	close(fd_dest);
	
	return 0;
}

int main(int argc, char const *argv[])
{
	const char *src_file_path = argv[1];
	const char *dest_file_path = argv[2];

	int ret = file_copy(src_file_path, dest_file_path);
	
	return 0;

}

2. 刪除文件夾及其下面的所有文件

直接看一個程序吧,在一個給定的主路徑下,通過當前時間創建子路徑,再在子路徑下寫入幾個文件,一段時間後(程序中是10秒),再將子路徑及其下面的文件全部刪除。

/* 用時間命名輸出文件,精確到毫秒 */
string get_output_image_filename(string output_dir)
{
	char part_name[100];
	char full_name[400];

	struct timeval curr_time;
	gettimeofday(&curr_time, NULL);

	int millisec = curr_time.tv_usec % 1000;   // Get the millisencond value

	struct tm *curtime;
	time_t lt;
	time(&lt);
	curtime = localtime(&lt);

	strftime(part_name, 100, "Img_%Y-%m-%d_%H-%M-%S", curtime);
	sprintf(full_name,"%s%s-%d.bmp",output_dir.c_str(), part_name, millisec);

	printf("full_img_name = %s \n", full_name);

	return (string)full_name;
	
}

/* 給定主存儲路徑,獲取以時間命名的下級路徑 */
string get_output_image_subdir(string main_dir)
{
	char sub_dir[100];
	char full_sub_dir[256];

	struct tm *curtime;
	time_t lt;
	time(&lt);
	curtime = localtime(&lt);

	strftime(sub_dir, 100, "Images_%Y-%m-%d_%H-%M-%S", curtime);
	
	sprintf(full_sub_dir,"%s%s/",main_dir.c_str(), sub_dir);

	printf("Images output subdir is: %s \n", full_sub_dir);

	if((access(full_sub_dir, F_OK) != 0) && (mkdir(full_sub_dir, S_IRWXU) < 0))
	{
		printf("Make output image dir failed!");

		return NULL;
	}

	return full_sub_dir;
	
}

/* 給定路徑和文件名,獲取文件的全路徑名稱 */
string get_file_path(const char* input_path, char* single_file_name)
{
	char full_file_path[300];
	strcpy(full_file_path, input_path);
	
	/* Make a full directory, like this: /home/ouputfile/ */
	if(full_file_path[strlen(input_path) - 1] != '/')
	{
		strcat(full_file_path , "/");
	}
	
	/* Make a full file path, like this: /home/outputfile/file1.txt */
	strcat(full_file_path, single_file_name);
	
	printf("The full file path is: %s \n", full_file_path);
	
	return (string)full_file_path;
	
}

/* 通過遞歸的方式刪除某個路徑下的所有文件,並刪除該路徑 */
bool delete_file(string file_path)
{
	DIR *dir;
	struct dirent *dirinfo;
	struct stat buf;
	string fullFilePath;
	lstat(file_path.c_str(), &buf);
	
	/* Check if the path is a regular file, if it is, remove it directly.
    If it is a directory, then remove the files first, and remove the directory at last. */	
	if(S_ISREG(buf.st_mode))   // Check if it is a regular file
	{
		remove(file_path.c_str());   
	}
	else if(S_ISDIR(buf.st_mode))  // Check if it is a directory
	{
		dir = opendir(file_path.c_str());
		if(NULL == dir)
		{
			printf("Open dir failed! \n");
			return false;
		}
		
		/* Remove sub directories recursively */
		while((dirinfo = readdir(dir)) != NULL)
		{
			fullFilePath = get_file_path(file_path.c_str(), dirinfo->d_name);
			if((strcmp(dirinfo->d_name, ".") == 0) || (strcmp(dirinfo->d_name, "..") == 0))
			{
				continue;    // Ignore dot and double dots in the directory
			}
			
			/* 對函數自身進行遞歸調用 */
			delete_file(fullFilePath.c_str());
			rmdir(fullFilePath.c_str());
			
			printf("Delete file path: %s \n", fullFilePath.c_str());
		}
		
		closedir(dir);
		
		/* 最後刪除主路徑 */
		rmdir(file_path.c_str());
	}
	
	return true;
	
}



/* Test for image writing */
int main()
{
	Mat Img = imread("test.bmp");
	
	/* Image write path */
	string image_path = "./Images/";   //主路徑
	if((access(image_path.c_str(), F_OK) != 0) && (mkdir(image_path.c_str(), S_IRWXU) < 0))
	{
		printf("Image output path can not accessed! \n");
		exit(1);
	}
	
	/* 獲取子路徑 */
	string sub_dir = get_output_image_subdir(image_path);
	string full_img_name;
	int i = 0;
	
	/* 將一個文件在創建的子路徑下寫入5次,形成5個文件,以備後續測試刪除功能 */
	while(i < 5)
	{
		full_img_name = get_output_image_filename(sub_dir);
		
		if(full_img_name.length() == 0)
		{
			printf("File name error! \n");
			exit(1);
		}
	
		imwrite(full_img_name, Img);
		
		sleep(1);
		
		i++;
	}
	
	sleep(10);
	
	/* 文件寫入10秒後刪除文件及其所在的子路徑 */
	bool is_del = delete_file(sub_dir);
	if(is_del)
	{
		printf("Successfully deleted the path and files. \n");
		
	}
	else
	{
		printf("Delete path and files failed. \n");
	}
	
	return 0;
}

上例中定義了一個函數:delete_file(string file_path),該函數通過對自己的遞歸調用實現路徑file_path及其下所有文件的刪除。在該函數中,用到的函數和結構體需要簡單說明下:

2.1 DIR

找到的定義如下:

struct __dirstream
{
	void *__fd;          //  pointer for descriptor
	char *__data;        // Directory block
	int __entry_data;    // Entry number `__data' corresponds to
	char *__ptr;         // Current pointer into the block
	int __entry_ptr;     //  Entry number `__ptr' corresponds to
	size_t __allocation;   // Space allocated for the block
	size_t __size;         // Total valid data in the block
	__libc_lock_define (, __lock)   // Mutex lock for this structure
};

typedef struct __dirstream DIR;

2.2 struct dirent

該結構體是用來獲取某文件夾目錄內容。定義如下,釋義來自百度百科。上例中是用來獲取某目錄下的文件名稱,即dirinfo->d_name。

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) 文件名,最長256字符 */
}

2.3 struct stat

上例中,該結構體用來存放某目錄的詳細信息,通過執行lstat(file_path.c_str(), &buf),將file_path表示的路徑的詳細信息存儲在stat類型的buf結構體中。後面通過執行S_ISREG(buf.st_mode)、S_ISDIR(buf.st_mode)判斷當前路徑是常規文件,還是一個路徑。

struct stat 
{
	mode_t     st_mode;       //文件訪問權限
	ino_t      st_ino;       //索引節點號
	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;     //該文件所佔的磁盤塊
};

2.4 刪除文件remove()

函數原型如下,輸入參數可以是一個路徑,也可以是一個常規文件名。但如果是路徑,只能是空路徑,如果路徑非空,調用remove是無法將其刪除的,因此纔有上面例子中的遞歸調用。

#include <stdio.h>
int remove(char * filename);

2.5 路徑操作:

用到的幾個dir操作如下,比較簡單,不過多解釋。

#include<sys/types.h>
#include<dirent.h>

DIR* opendir (const char * path );
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dir);
int rmdir(const char *dirname );

 

發佈了56 篇原創文章 · 獲贊 56 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章