【Linux文件IO】Linux中标准IO的API的描述和基本用法
Linux中标准IO的API的描述和基本用法
- 一、标准IO相关API
- 1、文件的打开和关闭
- 示例代码:
- 2、文件的读写
- 示例代码:
- 用标准IO(fread、fwrite)实现文件拷贝(任何文件均可拷贝)
- 3、文件偏移设置
- 示例代码:
- 4、fgets fputs fgetc fputc gets puts putchar getchar putc getc
- 示例代码:
- (1) fgets按行读取数据
- (2) fputs写入数据到文件
- (3) fgets和fputs另外一个功能(标准输入和标准输出)
- (4) fgetc读取一个字符和fputc写入一个字符
- 5、判断是否到达文件末尾
- 示例代码:
- 6、fprintf和fscanf()
- 示例代码:
- 7、主动刷新缓冲区
- 示例代码:
- 二、对比系统IO和标准IO的区别
- 1、
- 2、
- 3、
一、标准IO相关API
1、文件的打开和关闭
注意:
- 总共有6中打开模式,不能自创别的模式,比如 “rw” 是非法的。
注意: - fclose函数涉及内存释放,不可对同一个文件多次关闭。
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
FILE * fp;
// 以只读方式打开文件,要求文件必须存在
// fp = fopen("1.txt", "r"); // 文件打开失败 提示: No such file or directory
// 以读写方式打开文件,要求文件必须存在
// fp = fopen("1.txt", "r+"); // 文件打开失败 提示: No such file or directory
// 以只写方式打开文件,不存在就新建,存在则清空
fp = fopen("1.txt", "w"); //
if (fp == NULL)
{
perror("文件打开失败\n");
return -1;
}
// 关闭文件
fclose(fp);
return 0;
}
2、文件的读写
//按照数据块来读取数据
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值(重点):成功 返回读取到的完整的数据块的个数
失败 -1
参数:ptr --》存放读取的内容
size(重点) --》要读取的数据块大小,字节
nmemb(重点) --》打算读取多少个数据块
stream --》要读取的那个文件
比如:read(fd,buf,100);
fread(buf,50,2); //读取2个数据块,每个数据块50个字节
fread(buf,20,5); //读取5个数据块,每个数据块20个字节
fread(buf,10,10); //读取10个数据块,每个数据块10个字节
fread(buf,1,100); //读取100个数据块,每个数据块1个字节
情况1:如果文件剩余的字节数>=100个字节,以上四种写法都可以成功读取100个字节
区别就是返回值不同
情况2:如果文件剩余的字节数<100个字节,以上四种写法都可以成功读取剩余所有的字节
区别就是返回值不同
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值(重点): 成功 nmemb是多少,返回值就是多少
参数:ptr --》存放要写入的内容
size(重点) --》要写入的数据块大小,字节
nmemb(重点) --》打算写入多少个数据块
stream --》要写入的那个文件
总结:无论write还是fwrite写入的字节数搞多了,都会找垃圾凑够需要写的字节数
fwrite第三个参数写的是多少,返回值就是多少
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/*
fread返回值:返回完整数据块个数
fwrite返回值:nmemb是多少,返回值就是多少
*/
int main(int argc, char const *argv[])
{
FILE *fp = fopen("1.txt", "r+");
int ret = 0;
if (fp == NULL)
{
perror("打开文件失败\n");
return -1;
}
char buf[20] = "helloword";
// ret = fread(buf, 10, 1, fp); // 读取1个数据块,数据块大小为10个字节 读取的内容是:1234567890
// fread(buf, 5, 2, fp); // 读取2个数据块,数据块大小为5个字节 读取的内容是:1234567890
// ret = fread(buf, 1, 10, fp); // 读取10个数据块,数据块大小为1个字节 读取的内容是:1234567890
// fread(buf, 2, 5, fp); // 读取5个数据块,数据块大小为2个字节 读取的内容是:1234567890
// ret = fread(buf, 6, 2, fp);
// printf("读取的内容是:%s\n", buf);
// printf("fread的返回值ret:%d\n", ret);
ret = fwrite(buf, 10, 1, fp);
printf("fwrite的返回值ret:%d\n", ret);
return 0;
}
用标准IO(fread、fwrite)实现文件拷贝(任何文件均可拷贝)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
int ret = 0;
FILE *fp1 = fopen("1.txt", "r+");
if (fp1 == NULL)
{
perror("打开文件失败\n");
return -1;
}
FILE *fp2 = fopen("new.txt", "w+");
if (fp1 == NULL)
{
perror("新建文件失败\n");
return -1;
}
while (1)
{
bzero(buf, 100);
// 每次读取100字节,即读取100个数据块,每个数据块1字节
ret = fread(buf, 1, 100, fp1);
// 读取完成则退出循环
if (ret == 0)
{
break;
}
// 写入到目标文件
fwrite(buf, 1, ret, fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
3、文件偏移设置
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
int ret = 0;
FILE *fp1 = fopen("1.txt", "r+");
if (fp1 == NULL)
{
perror("打开文件失败\n");
return -1;
}
// 从起始位置往后偏移5个字节,返回值与lseek不一样,0:成功, -1:失败
ret = fseek(fp1, 5, SEEK_SET);
printf("fseek的返回值是:%d\n", ret); // fseek的返回值是:0
// 获取当前光标距离起始位置的字节数
printf("当前光标距离起始位置的字节数:%ld\n", ftell(fp1)); // 当前光标距离起始位置的字节数:5
// 读取文件,从第六个字节开始读取
fread(buf, 1, 5, fp1);
// 偏移后读取的数据是:world 若读取数据有误,现在linux中手动删除(rm 1.txt)在新建(vim 1.txt)
printf("偏移后读取的数据是:%s\n", buf);
// 关闭文件
fclose(fp1);
return 0;
}
4、fgets fputs fgetc fputc gets puts putchar getchar putc getc
char *fgets(char *s, int size, FILE *stream); //按行读取数据,一次最多读取一行(遇到回车结束读取)
返回值:成功 返回读取的一行数据的首地址
失败 NULL
参数:s --》存放读取到的一行数据
size --》打算读取多少字节的数据
stream --》要从哪个文件读取一行
特点:假如一行只有10个字符
fgets(buf,5,myfile); //只能读取4个有效字符,最后一个fgets会帮你填充\0
fgets(buf,11,myfile); //前面10个是有效字符,第11个是\0
fgets(buf,12,myfile); //前面11个是有效字符(会把回车\n读取,windows上的回车是\r\n),第12个是\0
int fputs(const char *s, FILE *stream); //往一个文件中写入字符串
返回值:成功 >0 失败 -1
参数:s --》要写入的内容
stream --》要写入的那个文件
fputs有局限性(char *),只能写入字符串,但是fwrite可以写任意类型(void *)的数据
int fgetc(FILE *stream); //按字符读取数据,一次只能读取一个字节的数据
返回值:读取到的那个字符的ASCII码值
失败 -1
int fputc(int c, FILE *stream); //把c这个字符写入到stream表示的文件中
char *gets(char *s); //只能读取键盘输入的字符串,把字符串保存到s中
int puts(const char *s) //把s这个字符串在标准输出(液晶屏)上打印出来
int getc(FILE *stream); //按字符读取数据,一次只能读取一个字节的数据
int putc(int c, FILE *stream); //把c这个字符写入到stream表示的文件中
int getchar(void); //从IO缓冲区读取一个字符
int putchar(int c); //把c代表的字符在液晶屏上打印出来
示例代码:
(1) fgets按行读取数据
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
/*
fgets按行读取文件
特点:fgets遇到回车就结束读取,并且会把回车也读取出来
特点: 假如一行只有10个字符
fgets(buf,5,myfile); //只能读取4个有效字符,最后一个fgets会填充\0
fgets(buf,11,myfile); //前面10个是有效字符,第11个是\0
fgets(buf,12,myfile); //前面11个是有效字符(会把回车\n读取,windows上的回车是\r\n),第12个是\0
*/
int main(int argc, char const *argv[])
{
char buf[100] = {0};
int ret = 0;
FILE *fp1 = fopen("1.txt", "r+");
if (fp1 == NULL)
{
perror("打开文件失败\n");
return -1;
}
// 每一轮读取一行数据
// for (int i = 0; i < 3; i++)
// {
// bzero(buf, 0);
// fgets(buf, 100, fp1);
// printf("buf :%s\n", buf);
// }
/*
原始数据:
helloworld
你好
你最棒
执行结果:
buf :helloworld
buf :你好
buf :你最棒
*/
// 第二个参数需要设置到足够大,否则一直读取第一行数据直至读完才会读取第二行数据
bzero(buf, 100);
fgets(buf,5,fp1);
printf("buf :%s\n", buf);
bzero(buf, 100);
fgets(buf,5,fp1);
printf("buf :%s\n", buf);
bzero(buf, 100);
fgets(buf,5,fp1);
printf("buf :%s\n", buf);
/*
原始数据:
helloworld
nihaonihao
helloworld
执行结果:
buf :hell
buf :owor
buf :ld
*/
// 关闭文件
fclose(fp1);
return 0;
}
(2) fputs写入数据到文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
int ret = 0;
FILE *fp1 = fopen("1.txt", "r+");
if (fp1 == NULL)
{
perror("打开文件失败\n");
return -1;
}
// 写入字符串
fputs("hello", fp1);
fputs("world", fp1);
fseek(fp1, 0, SEEK_SET);
fread(buf, 1, 100, fp1);
printf("buf:%s\n", buf);
// 关闭文件
fclose(fp1);
return 0;
}
(3) fgets和fputs另外一个功能(标准输入和标准输出)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
// fgets读取键盘输入的字符串(标准输入)
printf("fgets从键盘输入一个字符串:");
fgets(buf, 100, stdin);
// fputs写入字符串到液晶屏(标准输出)
printf("fputs从液晶屏输出一个字符串:");
fputs(buf, stdout);
return 0;
}
/*
执行结果:
fgets从键盘输入一个字符串:nihao
fputs从液晶屏输出一个字符串:nihao
*/
(4) fgetc读取一个字符和fputc写入一个字符
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
int ret = 0;
FILE *fp1 = fopen("1.txt", "r+");
if (fp1 == NULL)
{
perror("打开文件失败\n");
return -1;
}
// 读取一个字节
ret = fgetc(fp1);
printf("读取到的内容:%c, %d\n", ret, ret); // 读取到的内容:h, 104
fputc('#', fp1);
fseek(fp1, 0, SEEK_SET);
fread(buf, 1, 100, fp1);
printf("写入#后的内容是:%s\n", buf); // 写入#后的内容是:h#lloworld
// 关闭文件
fclose(fp1);
return 0;
}
5、判断是否到达文件末尾
int feof(FILE *stream);
返回值:1 表示达到文件末尾
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
char buf[100] = {0};
FILE *fp = fopen("1.txt", "r+");
if (fp == NULL)
{
perror("打开文件失败\n");
return -1;
}
while(1)
{
bzero(buf, 100);
char *ret = fgets(buf, 100, fp);
printf("读取到一行的数据:%s\n", buf);
// 方法1:通过fgets和fread的返回值判断
// if (ret == NULL)
// {
// printf("读取完毕\n");
// break;
// }
// 方法2:使用feof函数判断
if (feof(fp) == 1)
{
printf("读取完毕\n");
break;
}
}
fclose(fp);
return 0;
}
/* 执行结果:
读取到一行的数据:h#lloworld
读取到一行的数据:nihao
读取到一行的数据:666666
读取完毕 */
6、fprintf和fscanf()
sprintf 拼接字符串
printf 打印字符串
int fprintf(FILE *stream, const char *format, ...); //按照指定格式,把数据合并写入到stream代表的文件中
int fscanf(FILE *stream, const char *format, ...); //按照指定格式,把数据读取出来
fscanf读取指定格式的数据
如果指定的格式是%s,fscanf会把整个文件内容都当成是字符串
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
/* fprintf 把字符串拼接好写入指定的文件中 */
char read_buf[100] = {0};
char *buf = "hello";
int year = 2025;
float score = 99.9;
FILE *fp = fopen("2.txt", "w+");
if (fp == NULL)
{
perror("打开文件失败\n");
return -1;
}
fprintf(fp, "%s%d-%f", buf, year, score);
// 写完后此时光标移至末尾,需要将光标重新移至开头
fseek(fp, 0, SEEK_SET);
// 读取文件
fread(read_buf, 1, 100, fp);
printf("read_buf:%s\n", read_buf); // read_buf:hello2025-99.900002
// 关闭文件
fclose(fp);
/* fscanf 把文件中的内容读取并拆分 */
char *write_buf = "2025-01-01";
int y,m,d;
FILE *fp2 = fopen("3.txt", "w+");
if (fp2 == NULL)
{
perror("打开文件失败\n");
return -1;
}
// 写入文件
fwrite(write_buf, 1, strlen(write_buf), fp2);
// 写入文件时会将光标移至文件末尾。需要将光标重新移至开头
fseek(fp2, 0, SEEK_SET);
// 把文件中的内容读取并拆分
fscanf(fp2, "%d-%d-%d", &y, &m, &d);
printf("年:%d\n", y);
printf("月:%d\n", m);
printf("日:%d\n", d);
return 0;
}
/*
执行结果:
read_buf:hello2025-99.900002
年:2025
月:1
日:1
*/
7、主动刷新缓冲区
正常情况下标准IO是带缓冲区:
情况一:缓冲区满了,自动刷新
情况二:缓冲区没有满,主函数return退出的时候也会自动刷新缓冲区
情况三:fclose关闭文件的时候也会刷新缓冲区
int fflush(FILE *stream);
返回值:成功:0 失败:-1
示例代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
int n = 0;
FILE *fp = fopen("4.txt", "r+");
if (fp == NULL)
{
perror("打开文件失败\n");
return -1;
}
while (1)
{
fwrite("hello", 1, 5, fp);
sleep(1);
fflush(fp); // 主动刷新缓冲区
}
fclose(fp);
// return 0;
}
二、对比系统IO和标准IO的区别
1、
- 系统IO采用文件描述符来表示文件
- 标准IO采用FILE*来表示文件
2、
系统IO 0 1 2
#define STDIN_FILENO 0 标准输入--》键盘
#define STDOUT_FILENO 1 标准输出--》液晶屏
#define STDERR_FILENO 2 标准错误输出--》液晶屏
标准IO stdin stdout stderr
FILE *stdin; 标准输入--》键盘
FILE *stdout; 标准输出--》液晶屏
FILE *stderr; 标准错误输出--》液晶屏
3、
- 系统IO没有缓冲区
- 标准IO带缓冲区