Linux学习-文件IOA1——用结构体和文件操作函数实现文件的拷贝
其实我们不必选用结构体去实现模仿拷贝功能的,但是为了锻炼我们的思维以及对结构体、文件操作函数的使用,所以我们就这样来折腾自己。
学习的过程就是将复杂的事情简单化,再将简单的事情复杂化,这样才会对只是理解更深刻透彻,运用的也会更加得心应手,我们在实际上遇到问题的时候也能从不同角度考虑问题了。(后面的注意事项要看,不然使用方法错误会浪费时间)
以下是参考代码以及注释:
#include<sys/types.h>//open头文件
#include<sys/stat.h>//open头文件
#include<fcntl.h>//open头文件
#include<unistd.h>//write、read、close头文件
#include<stdio.h>
#include<string.h>
#include<errno.h>//perror头文件
#include<stdlib.h>//memset头文件
#define ERROR -1 //宏定义-1的值
#define ERROR_P ((P_FI)ERROR) //为了方便Open_Function函数的返回值
#define SUCCESS 0 //宏定义0的值
typedef struct file_information{
int open_a_fd;//文件a的描述符
int open_b_fd;//文件b的描述符
int write_num;//每次读取文件的大小
char *pointer_a;//文件a的路径地址
char *pointer_b;//文件b的路径地址
}FI,*P_FI;//定义结构体类型
//-----初始化以及打开文件函数的定义-------------------------------------
P_FI Open_Function(char *argv_1,char *argv_2);
//-----写入文件数据函数的定义-------------------------------------------
int Write_Function(P_FI type);
//-----关闭释放文件空间函数的定义---------------------------------------
int Close_Function(P_FI type);
//-----初始化以及打开文件函数-------------------------------------------
P_FI Open_Function(char *argv_1,char *argv_2)
{
//-------初始化内存空间-----------------------------------
//给结构体opinter_strcut申请内存
P_FI opinter_strcut = (P_FI)malloc(sizeof(FI));
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(opinter_strcut == NULL)
{
printf("malloc opinter_struct");
}
//初始化,清空内存里面的乐色数据,防止数据乱码情况发生
memset(opinter_strcut,0,sizeof(FI));
//给pointer_a申请空间,存放路径地址
opinter_strcut->pointer_a = (char *)malloc(sizeof(*argv_1));
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(opinter_strcut->pointer_a == NULL)
{
perror("malloc pointer_a");
//返回一个错误时候的指针,我们将-1强制类型转化,上面有宏定义
return ERROR_P;
}
//给pointer_b申请空间,存放路径地址
opinter_strcut->pointer_b = (char *)malloc(sizeof(*argv_2));
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(opinter_strcut->pointer_b == NULL)
{
perror("malloc pointer_b");
//返回一个错误时候的指针,我们将-1强制类型转化,上面有宏定义
return ERROR_P;
}
//初始化,清空内存里面的乐色数据,防止数据乱码情况发生
memset(opinter_strcut->pointer_a,0,sizeof(*argv_1));
//初始化,清空内存里面的乐色数据,防止数据乱码情况发生
memset(opinter_strcut->pointer_b,0,sizeof(*argv_2));
//------打开文件,并且赋值到结构体里面----------------------
//初始化掩码,防止后面给权限的时候出错
umask(0000);
//打开文件a,并把文件描述符赋值到结构体对应的变量open_a_fd
opinter_strcut->open_a_fd = open(argv_1,O_RDONLY);
//打开文件b,并把文件描述符赋值到结构体对应的变量open_b_fd
opinter_strcut->open_b_fd = open(argv_2,O_WRONLY | O_CREAT,0777);
//定义每次读取的数据大小,赋值给结构体变量write_num
opinter_strcut->write_num = 20;
//函数返回值,返回一个指针
return opinter_strcut;
}
//-----写入文件数据函数的定义-------------------------------------------
int Write_Function(P_FI type)
{
//-----定义空间作为读取数据的缓存区------------------------
char array[type->write_num];
//定义两个变量接受read和write的返回值,在while外面定义就不用每次循环都申请一次
//优化了程序运行
int read_ret,write_ret;
//循环读取数据,写入数据
while(1)
{
//初始化,清空上一次的数据,防止上一次的数据残留会使新数据出现乱码
memset(array,0,sizeof(type->write_num));
//读文件a,read_ret接收返回值,进行判断是否成功
read_ret = read(type->open_a_fd,array,type->write_num);
//判断是否成功
//情况1:当返回值是-1时,说明read失败,退出;
if(read_ret == ERROR)
{
perror("read a");
return ERROR;
}
//情况2:当返回值是0的时候,说明已经读取完、写完数据,退出;
else if(read_ret == SUCCESS)
{
printf("文件读取完成!\n");
return SUCCESS;
}
else
//情况3:说明read还在读取数据,你们玩吗就马上将读取的数据写入文件b里面
{
//写入文件b,write_ret接收返回值,进行判断是否成功
write_ret = write(type->open_b_fd,array,read_ret);
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(write_ret == ERROR)
{
perror("write");
return ERROR;
}
}
}
}
//-----关闭释放文件空间函数---------------------------------------------
int Close_Function(P_FI type)
{
//关闭文件a
int close_ret_a = close(type->open_a_fd);
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(close_ret_a == ERROR)
{
perror("close a");
}
//关闭文件b
int close_ret_b = close(type->open_b_fd);
//判断是否成功,要养成良好的习惯,即使以后用不到,也要培养这个思维
if(close_ret_b == ERROR)
{
perror("close b");
}
//释放结构体里面open_a_fd申请的空间,
//不能先释放结构体的内存,因为这样做的话我们会找不到open_a_fd的位置;
free(type->pointer_a);
//释放结构体里面open_b_fd申请的空间,
//不能先释放结构体的内存,因为这样做的话我们会找不到open_b_fd的位置;
free(type->pointer_a);
//最后再释放结构体。
free(type);
return SUCCESS;
}
//-----主函数----------------------------------------------------------
int main(int argc,char *argv[])
{
//-----初始化以及打开文件函数的调用----------------------------------
P_FI open_p = Open_Function(argv[1],argv[2]);
//判断是否成功
if(open_p == ERROR_P)
{
printf("打开文件失败!\n");
return ERROR;
}
//-----写入文件数据函数的调用---------------------------------------
int write_ret = Write_Function(open_p);
//判断是否成功
if(write_ret == ERROR)
{
printf("写入文件失败!\n");
return ERROR;
}
//-----关闭释放文件空间函数的调用-------------------------------------
Close_Function(open_p);
//主函数返回值
return SUCCESS;
}
注意:这样写我们运行的时候不是./文件名 哦,是./文件名 要被拷贝的文件名 拷贝到文件的文件名。例如我要将a.txt的数据拷贝到b.txt,在main文件上执行,那么我的运行命令格式就是:./main a.txt b.txt
代码略长。加油小白菜!