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(<);
curtime = localtime(<);
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(<);
curtime = localtime(<);
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 );