命令功能要能够完成实际应用的要求,实现拷贝命令的各项功能(参考cp命令的功能和用法),如:单参数、双参数等各种参数格式的识别,文件的连接,目录下内容的递归复制,拷贝时磁盘空间的检查等,目标文件重名的提示等。 设计中要注意: 结合系统拷贝实际进行认真地分析,确定设计的拷贝命令要实现的各种复制功能、输入形式,错误处理方法; 在上一步基础上确定出拷贝命令的实际需要,设计命令的基本功能、程序结构和处理流程,学习和选择合理的系统调用; 做出必要的流程图和程序说明; 编写各基本功能代码; 运行调试,验证程序功能,反复修改自己的设计和实现; 完成拷贝程序设计。
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <stdlib.h>
#include <fcntl.h> //头文件
int use(char *copied_file,char *destination_use)
{
//计算新建文件(目录)所在文件系统的剩余容量
struct statfs diskInfo;
statfs(destination_use,&diskInfo);
double blocksize = diskInfo.f_bsize;// 每个block里面包含的字节数
double freesize = blocksize*diskInfo.f_bfree; //计算文件所在文件系统的剩余空间大小,每个block里面包含的字节数*可用块数
printf("剩余空间大小:%.2fKB\n",freesize);
//计算被复制文件大小
struct stat buf;
stat(copied_file, &buf);
double filesize = buf.st_size;
printf("被复制的文件大小为: %.2fKB\n", filesize);
if(freesize>filesize)
{
printf("空间足够,文件可以复制!\n");
return 1;
}
else
{
printf("空间不足,文件不可以复制!\n");
return 0;
}
return 0;
}
int CopyDir(char *path1,char *path2) //复制目录
{
DIR *dir;
char filepath1[255];
char filepath2[255];
char dirpath1[255];
char dirpath2[255];//存放目录或者文件路径
dir = opendir(path1);//打开文件夹
if(dir==0) //无法打开则跳过
{
printf("open %s failed!\n",path1); return -1;
}
struct dirent *stdir; //dirent结构体
while(1)//循环读取
{
stdir = readdir(dir); //读取目录内容
if(stdir ==0) break; //遍历完一整个文件夹就停止循环
if(!strcmp(stdir->d_name,"..")||!strcmp(stdir->d_name,"."))//过滤..和. 防止读取时出错
{
continue;
}
if(stdir->d_type == 8)//判断如果是文件则复制
{
sprintf(filepath1,"%s/%s",path1,stdir->d_name);//拼接路径全名(目录名+文件名)
sprintf(filepath2,"%s/%s",path2,stdir->d_name);
if(access(filepath2,F_OK)==0)//判断是否有同名的文件
{
printf("ERROR:有同名文件%s存在,停止复制!\n",filepath2);
exit(1);//退出程序
}
printf("%s\n",&filepath2);//打印文件路径
int fd1 =open(filepath1,O_RDONLY); //打开被复制的文件
if(fd1<0){perror("fd1");printf("open error!");return -1;}
int fd2 = open(filepath2,O_RDWR|O_CREAT,0777); //新建新文件
if(fd2<0){perror("fd2");return -1;}
while(1) //拷贝,系统IO的拷贝,根据读取的字节数写入
{
char buf[1024]={0};
int size=read(fd1,buf,1024);
if(size<=0)break;
write(fd2,buf,size);
}
close(fd1);close(fd2);
}
else if(stdir->d_type == 4) //判断是文件夹,则拼接路径并且创建
{
sprintf(dirpath1,"%s/%s",path1,stdir->d_name); //拼接目录全名(当前目录名 + 子目录名)
sprintf(dirpath2,"%s/%s",path2,stdir->d_name);
printf("%s\n",&dirpath2);
if(access(dirpath2,F_OK)==0)
{
printf("ERROR:有同名目录%s存在,停止复制!\n",dirpath2);
exit(1);
}
mkdir(dirpath2,0644);//创建目录
CopyDir(dirpath1,dirpath2);//调用自己函数CopyDir(),递归复制文件夹
}
}
closedir(dir);//关闭目录
return 0;
}
int CopyFile(char *file1,char *file2){
if(access(file2,F_OK)==0)
{
printf("ERROR:有同名文件存在,停止复制!");
exit(1);
}
int fd1 =open(file1,O_RDONLY);
if(fd1<0){perror("fd1");printf("no!");return -1;}
int fd2 = open(file2,O_RDWR|O_CREAT,0644);
if(use(file1,file2)==1){ //打开已存在的文件 //新建新文件
if(fd2<0){perror("fd2");return -1;}
while(1) //拷贝,系统IO的拷贝,根据读取的字节数写入
{
char buf[1024]={0};
int size=read(fd1,buf,1024);
if(size<=0)break;
write(fd2,buf,size);
}
close(fd1);close(fd2);
return 0;}
else{_exit(2);}
}
int main(int argc,char *argv[])
{
if(argc != 4)//命令使用格式则报错
{
printf("请输入正确的格式,例如:./c [选项-f:文件,-d:目录] 源文件 目的文件 \n");
return -1;
}
if(!strcmp(argv[1],"-d"))//目录
{
mkdir(argv[3],0644);//可以在CopyDir()函数里使用,此但处创建目录是为了适配use()判断磁盘空间函数,防止重复输出,
if(use(argv[2],argv[3])==1)
{
if (CopyDir(argv[2],argv[3])==0)
{
printf("目录复制成功!!!!\n");
}
}
else{_exit(2);}//空间不足则停止复制
}
if(!strcmp(argv[1],"-f"))//文件
{
if (CopyFile(argv[2],argv[3])==0)
{
printf("文件复制成功!!!!\n");
}
}
}