文章目录
一、文件I/O基本概念
关于文件IO,涉及以下基本概念:文件描述符&系统调用接口
下面以思维导图的形式梳理这几个知识点:
思维导图源文件在此:Linux_文件IO.xmind
二、demo举例
下面记录linux文件操作如下四个基本接口:
- 备注:全文分为两个demo。demo1为接口的基本使用方法,供学习理解使用。demo2考虑了所有的错误场景处理,一般工程中会使用demo2 *
open() /* 打开文件 */
read() /* 读文件 */
write() /* 写文件 */
close() /* 关闭文件 */
2.1 demo1:四大接口基本用法
- 注意:此demo仅仅是当做学习理解读写文件接口的基本操作来使用。
一般情况下,由于读写文件时可能会出现各种错误,正常工程中需要考虑处理所有的错误,如果要全部读取文件,一直到文件末尾(EOF),此demo并不能适用于工程中,常见工程中的用法请移步之后的demo。
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd_src = 0;
int fd_dest = 0;
ssize_t len_src = 0;
ssize_t len_dest = 0;
char buf[1000];
printf("start:\r\n");
/* open file */
fd_src = open("src.txt", O_RDONLY);
if (fd_src == -1) {
perror("Open src failed:");
return -1;
}
fd_dest = open("dest.txt", O_RDWR | O_TRUNC | O_CREAT, 0664);
if (fd_dest == -1) {
perror("Open dest failed:");
return -1;
}
/* read file to buff */
memset(buf, 0, sizeof(buf));
len_src = read(fd_src, (void *)buf, sizeof(buf));
if (len_src == -1) {
perror("Read failed:");
return -1;
}
/* print buff */
printf("%s\r\n", buf);
/* write file */
len_dest = write(fd_dest, (const char *)buf, strlen(buf));
if (len_dest == -1) {
perror("Write failed:");
return -1;
}
memset(buf, 0, sizeof(buf));
/* close file */
close(fd_src);
close(fd_dest);
printf("end!\r\n");
return 0;
}
2.2 demo2:四大接口在工程中常见用法
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
int fd_src = 0;
int fd_dest = 0;
int len; /* 想要读取or写入的字节长度 */
char buf[1000]; /* 缓冲区:保存读出的内容 */
char *pbuf = buf;
ssize_t ret;
printf("start:\r\n");
/* 打开文件 */
fd_src = open("src.txt", O_RDONLY);
if (fd_src == -1) {
perror("Open src failed:");
return -1;
}
fd_dest = open("dest.txt", O_RDWR | O_TRUNC | O_CREAT, 0664);
if (fd_dest == -1) {
perror("Open dest failed:");
return -1;
}
/* 读文件(src.txt)
* len:需要读取的字节长度
* ret:读取到的字节长度
*/
len = sizeof(buf);
memset(buf, 0, sizeof(buf));
while ((len != 0) && ((ret = read(fd_src, (void *)buf, len)) != 0)) {
if (ret == -1) {
if (errno == EINTR) {
continue;
}
perror("read:");
break;
}
len = len - ret;
pbuf = pbuf + ret;
}
/* 写文件(dest.txt) */
pbuf = buf;
len = strlen(buf);
while ((len != 0) && ((ret = write(fd_dest, buf, len)) != 0)) {
if (ret == -1) {
if (errno == EINTR) {
continue;
}
perror("write:");
break;
}
len = len - ret;
pbuf = pbuf + ret;
}
/* 关闭文件 */
close(fd_src);
close(fd_dest);
printf("end!\r\n");
return 0;
}
2.2.1关于read(),主要是下面这一段代码:
/* len_src:要读取的数据长度
* ret:读文件接口read()的返回值,表示读取到的数据长度
*/
while ((len_src != 0) &&
((ret = read(fd_src, (void *)pbuf, len_src)) != 0)) {
if (ret == -1) {
if (errno == EINTR) {
continue;
}
perror("read:");
break;
}
len_src = len_src - ret;
pbuf = pbuf + ret;
}
释义:
- (1)read函数表示:从文件描述符指向位置开始读取文件到buff中,返回值为读取的长度,如果返回-1表示读取失败,错误码在errno中保存,如果为0表示读取0个字节。
- (2)如果要读取数据长度len_src为0,那直接跳过,不如不读
- (2)从fd_src文件中读取数据到pbuf缓冲区中,需要读出len_src长度
- (3)返回值ret如果为-1,读取失败则处理失败
- (4)如果读取成功,判断【要读取的长度 - 已读取到的长度】是否为0,如果为0则读取结束(因为有时候可能会读取失败或者读取中断,所以减去读取到的长度跟需要读的长度进行判断)
- (5)碰到EOF也表示读取文件到末尾了,需要结束了。
2.2.2 关于write(),主要是下面这段代码
/* 写文件(dest.txt) */
/* 将buf中的字符串写入到fd_dest中 */
pbuf = buf;
len = strlen(buf);
while ((len != 0) && ((ret = write(fd_dest, buf, len)) != 0)) {
if (ret == -1) {
if (errno == EINTR) {
continue;
}
perror("write:");
break;
}
len = len - ret;
pbuf = pbuf + ret;
}
释义:
- (1)write函数表示:从文件描述符fd引用文件的当前位置开始,将buf中的最多count个字节写入文件中。写入错误返回-1,成功时返回写入的字节数并更新文件位置。
- (2)要写入的长度不为零,就开始写入,写入之后返回值ret不为0表示写入成功或失败,进循环,循环中进行-1判错。
- (3)写入ret个字节以后,将想要写入的长度减去已写入的长度ret,并且缓冲区指针偏移ret为已经写入的长度。
- (4)再次循环时,如果len为0了表示写够了,跳出循环。