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 );