目录
一、read和write(系统IO)
代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#define ONCE_GET_SIZE 1
int Get_File_Descriptor(const char *pathname, int flags, mode_t mode); // 获取文件描述符
int Read_File_Date(int file_fd, char *buf, size_t size); // 读数据
int Write_File_Date(int file_fd, char *buf, size_t size); // 写数据
int Close_File_Descriptor(int file_fd); // 关闭文件
int Copy(int fdin, int fdout, char *buf); // 文件拷贝功能
/*
功能: 获取文件描述符
pathname: 文件路径
flags: 说明此函数的多个选择项
mode: 新建文件的访问权限,等于0则表示不需要创建
返回值: 错误返回-1,正确返回文件描述符
*/
int Get_File_Descriptor(const char *pathname, int flags, mode_t mode)
{
int fd;
if (!mode)
{
fd = open(pathname, flags);
}
else
{
umask(0000);
fd = open(pathname, flags, mode);
}
if (fd == -1)
{
perror("open error ");
return -1;
}
return fd;
}
/*
功能: 读取数据
file_fd: 要读文件的文件描述符
buf: 存放读取的数据
size: 读取数据的大小
返回值: 错误返回-1,正确返回读出的字节数量
*/
int Read_File_Date(int file_fd, char *buf, size_t size)
{
size_t read_ret = read(file_fd, buf, size);
if (read_ret == -1)
{
perror("write error");
return -1;
}
return read_ret;
}
/*
功能: 写入数据
file_fd: 要写文件的文件描述符
buf: 存放写入的数据
size: 读取数据的大小
返回值: 错误返回-1,正确返回写入的字节数量
*/
int Write_File_Date(int file_fd, char *buf, size_t size)
{
size_t write_ret = write(file_fd, buf, size);
if (write_ret == -1)
{
perror("write error");
return -1;
}
return write_ret;
}
/*
功能: 文件拷贝
fdin: 源文件
fdout: 目标文件
buf: 数据
返回值: 错误返回-1,正确返回0
*/
int Copy(int fdin, int fdout, char *buf)
{
ssize_t read_size, write_size;
while ((read_size = Read_File_Date(fdin, buf, ONCE_GET_SIZE)) > 0)
{
if ((write_size = Write_File_Date(fdout, buf, ONCE_GET_SIZE)) != read_size)
{
perror("copy error");
return -1;
}
}
return 0;
}
/*
功能: 关闭文件
返回值: 错误返回-1,正确返回0
*/
int Close_File_Descriptor(int file_fd)
{
if (close(file_fd) == -1)
{
perror("close error");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("输入参数有误!\n");
return -1;
}
int fdin = Get_File_Descriptor(argv[1], O_RDONLY, 0);
if (fdin == -1)
{
printf("源文件失败!\n");
return -1;
}
char buf[ONCE_GET_SIZE]; // 接受读出的数据
memset(buf, 0, sizeof(buf));
int fdout = Get_File_Descriptor(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0777);
if (fdout == -1)
{
printf("目标文件打开失败!\n");
return -1;
}
Copy(fdin, fdout, buf); // 拷贝
if (Close_File_Descriptor(fdin) == -1)
{
printf("源文件关闭失败\n");
return -1;
}
if (Close_File_Descriptor(fdout) == -1)
{
printf("目标文件关闭失败\n");
return -1;
}
return 0;
}
运行格式
gcc 文件拷贝.c -o cp
./cp 源文件路径 目的文件路径
二、fread和fwrite(标准IO)
代码
#include <stdio.h>
#include <string.h>
#define SIZE 1
#define NMEMB 1 // 每次读 1*1 个字节,如果需要读别的大小请看下面的
#define ERR -1
int File_Copy(const char *src, char *dest);
int File_Copy(const char *src, char *dest)
{
FILE *fp_src = fopen(src, "r");
FILE *fp_dest = fopen(dest, "w");
if (fp_src == (FILE *)NULL || fp_dest == (FILE *)NULL)
{
perror("fropen error");
return ERR;
}
char buf[SIZE * NMEMB + 1];
while (1)
{
memset(buf, 0, sizeof(buf));
if (fread(buf, SIZE, NMEMB, fp_src) < NMEMB)
{
if (feof(fp_src))
{
printf("拷贝完成!\n");
break;
}
if (ferror(fp_src))
{
perror("拷贝失败!");
return -1;
}
}
if (fwrite(buf, SIZE, NMEMB, fp_dest) < NMEMB)
{
perror("fwrite error");
return -1;
}
}
if (fclose(fp_src) == ERR || fclose(fp_dest) == ERR)
{
perror("fclose error");
return ERR;
}
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("参数有误!\n");
return ERR;
}
if (File_Copy(argv[1], argv[2]) == ERR)
{
printf("拷贝失败!\n");
return ERR;
}
return 0;
}
运行格式
gcc 文件拷贝.c -o cp
./cp 源文件路径 目的文件路径
补充:关于每次读多个字节的
注意:前面是每次读 1*1的所以不需要考虑最后一组,但那样太慢了
1.fwrite的原理
所以每次写入的数据是 size * nmemb 的字节数
所以如果循环读写的代码如下时,也就是每次读4个字节。
#define SIZE 2
#define NUM 2
while (1)
{
memset(buf, 0, sizeof(buf));
int read_ret = fread(buf, SIZE, NUM, fdin);
if (read_ret < NUM)
{
if (feof(fdin))
{
printf("拷贝完成!\n");
break;
}
if (ferror(fdin))
{
return -1;
}
}
if (fwrite(buf, SIZE, NUM, fdout) < NUM)
{
printf("不够哦\n");
return -1;
}
}
如果数据不是4的倍数时,则最后一组数据不会正确读入文件,但会读入buf,则这时候就需要ftell函数
注意:光标每次移动的距离就是 size * nmemb,所以最后一组数据feof会成立
2.ftell
ftell()函数主要用来读取,当前光标在文件中的位置。它的参数只有一个,就是需要读取的文件指针,返回值的类型是long,数字的大小代表当前光标距离文件起始处的字节数。
改进如下:
改进代码
char buf[SIZE * NUM + 1];
int start = 0, end = 0;
while (1)
{
memset(buf, 0, sizeof(buf));
start = ftell(fdin);
int read_ret = fread(buf, SIZE, NUM, fdin);
if (read_ret < NUM)
{
if (feof(fdin))
{
end = ftell(fdin);
if(fwrite(buf, end - start, 1, fdout) < 1)//读最后的一组数据
{
perror("error");
return -1;
}
printf("拷贝完成!\n");
break;
}
if (ferror(fdin))
{
return -1;
}
}
if (fwrite(buf, SIZE, NUM, fdout) < NUM)
{
printf("不够哦\n");
return -1;
}
}
三、fgets和fputs
代码
#include <stdio.h>
#include <string.h>
#define SIZE 256 //一次性拷贝的量
#define ERR -1
int File_Copy(const char *src, char *dest);
int File_Copy(const char *src, char *dest)
{
FILE *fp_src = fopen(src, "r");
FILE *fp_dest = fopen(dest, "w");
if (fp_src == (FILE *)NULL || fp_dest == (FILE *)NULL)
{
perror("fropen error");
return ERR;
}
char buf[SIZE + 1];
while (1)
{
memset(buf, 0, sizeof(buf));
if (fgets(buf, SIZE, fp_src) == NULL)
{
if (feof(fp_src))
{
printf("拷贝完成!\n");
break;
}
if (ferror(fp_src))
{
perror("拷贝失败!\n");
return -1;
}
}
if (fputs(buf, fp_dest) == EOF)
{
perror("fputs errpr");
return -1;
}
}
if (fclose(fp_src) == ERR || fclose(fp_dest) == ERR)
{
perror("fclose error");
return ERR;
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("参数有误!\n");
return ERR;
}
if (File_Copy(argv[1], argv[2]) == ERR)
{
printf("拷贝失败!\n");
return ERR;
}
return 0;
}
运行格式
gcc 文件拷贝.c -o cp
./cp 源文件路径 目的文件路径
四、注意
第三种fgets和fputs拷贝除文本以外的文件,可能会出错
原因是fputs到 '\0' 就停止,不会将 '\0' 写进去