一、实验目的:
(1)掌握Linux目录操作方法,包括打开目录、关闭目录、读取目录文件
(2)掌握Linux文件属性获取方法,包括三个获取Linux文件属性的函数、文件属性解析相关的宏
(3)掌握POSIX与ANSI C文件I/O操作方法,包括打开文件、关闭文件、创建文件、读写文件、定位文件
二 、实验原理:
(1)cp命令与命令行参数
UNIX/Linux中通过在shell中输入命令名(或可执行文件名)来启动程序,在命令名(可执行文件名)之后可以跟随一系列字符串(通过空格分割), 这些字符串就是命令行参数,例如:
cp [参数] <源文件路径> <目标文件路径>
cp /usr/local/src/main.c /root/main.c(文件到文件复制)
cp /usr/local/src/main.c /root (文件到目录复制)
cp –r /usr/local/src /root(递归复制,用于目录到目录的复制)
(2)实现文件到文件的拷贝
利用POSIX API在Linux系统上编写应用程序,仿写cp命令的部分功能,将源文件复制到另外一个文件或复制到另外一个目录。源文件路径和目标文件路径通过命令行参数来指定
1、将test1.text复制成test2.txt:
[test@linux test]$ ./mycp /home/test1.txt /usr/test2.txt
2、将test1.txt复制到/tmp目录中:
[test@linux test]$ ./mycp /home/test1.txt /tmp(目录)
(3)应用程序命令行参数获取
UNIX/Linux中C语言应用程序的启动函数是main
操作系统通过C启动例程来启动C程序,启动例程会从标准输入获取应用程序的命令行参数,并且将这些参数传递给main函数,例如,main函数定义:
int main(int argc, char* argv[])
形式参数:
argc :整形,命令行输入参数的个数
argv:字符串数组,以字符串形式存储的命令行参数
(4)打开关闭目录
常用函数:opendir,closedir
头文件:dirent.h
函数定义:
DIR * opendir(const char * name);
打开参数name指定目录,并使一个目录流与它关联;目录流类似于C库函数中的文件流;失败返回NULL
int closedir(DIR *dir);
关闭指定目录流,释放相关数据结构;成功返回0;失败返回-1。
(5)读取目录文件
常用函数:readdir
头文件:sys/types.h;dirent.h
函数定义:
struct dirent * readdir(DIR * dir);
读取目录流标识的目录文件;目录文件是一系列目录项的列表,每执行一次该函数返回指向当前读取目录项结构的指针;如果到达目录结尾或者有错误发生则返回NULL。
(7)获取文件属性
常用函数:stat,lstat
头文件: sys/stat.h
函数定义:
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
两个函数参数相同,功能类似;读取path参数所指定文件的文件属性并将其填充到buf参数所指向的结构体中;对于符号链接文件,lstat返回符号链接文件本身的属性,stat返回符号链接引用文件的文件属性
(8)判断文件类型宏
是否为普通文件: S_ISREG(st_mode)
是否为目录文件 S_ISDIR(st_mode)
是否为字符设备 S_ISCHR(st_mode)
是否为块设备 S_ISBLK(st_mode)
是否为FIFO S_ISFIFO(st_mode)
是否为套接字 S_ISSOCK(st_mode)
是否为符号连接 S_ISLINK(st_mode)
五、实验内容:
利用POSIX API(文件操作也可以使用ANSI C标准I/O库)编程实现cp –r命令,支持将源路径(目录)中的所有文件和子目录,以及子目录中的所有内容,全部拷贝到目标路径(目录)中。
参考代码:
#include
#include
#include
#include
#include
//文件拷贝函数
void copy_file(const char *src, const char *dst) {
FILE *source, *destination;
char ch;
source = fopen(src, "rb");
destination = fopen(dst, "wb");
while ((ch = fgetc(source)) != EOF) {
fputc(ch, destination);
}
fclose(source);
fclose(destination);
}
//目录拷贝函数
void copy_directory(const char *src, const char *dst) {
DIR *dir;
struct dirent *entry;
struct stat file_stat;
char src_path[256];
char dst_path[256];
dir = opendir(src);
if (dir == NULL) {
perror("Error opening source directory");
exit(-1);
}
// 如果目的目录不存在则创建
mkdir(dst, 0777);
while ((entry = readdir(dir)) != NULL) {
// 跳过"."跟".."
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// 获取源路径跟目的路径
snprintf(src_path, sizeof(src_path), "%s/%s", src, entry->d_name);
snprintf(dst_path, sizeof(dst_path), "%s/%s", dst, entry->d_name);
if (stat(src_path, &file_stat) == -1) {
perror("Error getting file stat");
exit(-1);
}
if (S_ISDIR(file_stat.st_mode)) {
// 递归拷贝目录
copy_directory(src_path, dst_path);
} else {
// 拷贝文件
copy_file(src_path, dst_path);
}
}
closedir(dir);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s source destination\n", argv[0]);
exit(-1);
}
copy_directory(argv[1], argv[2]);
printf("Copy complete!!!!\n");
return 0;
}