介绍
标准I/O是C语言库,不仅在UNIX系统,在其他操作上也可以使用。
标准I/O在系统调用函数基础上构造的,增加了一个缓冲机制,它便于用户使用。
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
功能:打开文件参数:
path:文件的路径mode:打开方式
r 或 rb:打开只读文件,该文件必须存在。
r+ 或 rb+:打开可读写的文件,该文件必须存在。
w 或 wb:以写的方式打开文件,文件不存在,则创建。文件存在,则清空。
w+ 或 wb+:以读写的方式打开文件,文件不存在,则创建。文件存在,则清空。
a 或 ab:以追加的方式打开文件(写),文件不存在,则创建。
文件存在,则再文件的末尾追加。
a+ 或 ab+:以追加的方式打开文件(读写),文件不存在,则创建。
文件存在,则再文件的末尾追加。
返回值:
成功: FILE * (流指针 === 结构体指针)
失败: NULL
注意:当给定 “b” 参数时,表示以二进制方式打开文件。
FILE:系统会自动为使用的文件在内存中开辟一片空间,来存储文件的详细信息,这个空间的数据类型为结构体类型。
FILE *:流指针,在标准I/O中,每次打开一个文件都会返回一个流指针,我们也得用同样类型的FILE *去接收这个流指针,这个流指针则描述了一个文件,所有的标准I/O都是围绕着文件来进行的。
同一个文件可以存在多个流指针。标准I/O函数测试当前系统最大能打开的文件个数为1021,其实为:1024。因为在系统中我们使用的输入、输出、错误提示都是文件。这三个文件分别是:标准输入流、标准输出流、标准错误流,占了1024里的0、1、2。
打开我们的终端时系统就默认打开了3个流指针:
- stdin (标准输入,终端进行输入)
- stdout(标准输出,终端打印出来)
- stderr(标准错误,终端打印出来)
int fclose(FILE *fp);
功能:关闭fopen打开的文件
参数:
fp:流指针
为什么要关闭一个文件?
- 防止其它进程操作这个文件
- 释放掉这个结构体的占用的资源
FILE *freopen(const char *path, const char *mode, FILE *stream);
功能:改变流指针的指向
参数:
path:文件的路径名
mode:打开方式
stream:流指针
int fgetc(FILE *stream);
功能:读取一个字节的数据
参数:
stream:流指针
返回值:
成功:返回这个字节
失败:-1
int fputc(int c, FILE *stream);
功能:写入一个字节的数据
参数:
c:字节
stream:流指针
#include <stdio.h>
#include <unistd.h>
/**
* 向终端循环打印'X'
*/
int main(int argc, char *argv[])
{
// 因为每一个终端都是一个文件: pts/xxx 这个就是终端对应的文件。
// 这个文件的名字是以数字命名的,存储在 : /dev/pts/xxx 这些文件是由linux系统自动创建。
// 当打开一个终端时,就会重建一个新的文件与之对应 stdin、stdout、stderr 都指向的是同一个文件(终端文件)。
FILE *fp = fopen("/dev/pts/1", "r+"); // 以读写的方式打开我们新开的终端文件
if (NULL == fp)
{
perror("fopen"); // 判断返回值
return -1;
}
while (1)
{
fputc('x', fp); // 调用函数fputc循环打印x
fputc('\n', fp);
sleep(2); // 用延时函数2秒打印一个
}
return 0;
}
int fflush(FILE *stream);
功能:将缓冲区中的内容写到stream所指的文件中去。若stream为NULL,则会将所有打开的文件进行数据更新。
参数:
stream:流指针
fflush(stdin):刷新缓冲区,将缓冲区内的数据清空并丢弃。
fflush(stdout):刷新缓冲区,将缓冲区内的数据输出到设备。
char *fgets(char *s, int size, FILE *stream);
功能:从文件读取一行的数据并且写入到内存空间
参数:
s:内存地址,也可以在内存上定义一片空间
size:内存空间的大小 N
stream:流指针
返回值:
成功:返回读取字符的首地址
失败:NULL
int fputs(const char *s, FILE *stream);
功能:向文件写入一行数据
参数:
s:内存地址,开辟的存储空间已经有数据存在
stream:流指针
返回值:
成功:1
失败:-1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* copy指令:把一个文件的内容复制到另一个文件内
*/
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("%s src_file dest_file\n", argv[0]); // 如果命令行参数少于3个,则打印提示信息
}
FILE *fp1 = fopen(argv[1], "r"); // 定义第一个流指针,命令行第二个参数写文件名,打开这个文件
if (NULL == fp1)
{
perror("fopen");
return -1;
}
FILE *fp2 = fopen(argv[2], "w"); // 定义第二个流指针,命令行第二个参数写文件名,打开这个文件
if (NULL == fp2)
{
perror("open");
return -1;
}
char buf[100] = {0}; // 我们从第一文件读的数据得存储到内存
while (1)
{
char *p = fgets(buf, sizeof(buf), fp1); // 判断函数是否成功执行
if (NULL == p)
{
// 读取最后跳出循环
printf("while break\n");
break;
}
fputs(buf, fp2); // 把内存的内容写入到第二个流指针打开的文件中
}
printf("Copy Sucess..\n");
fclose(fp1);
fclose(fp2);
return 0;
}
int fseek(FILE *stream, long offset, int whence);
功能:定位文件指针
参数:
stream:流指针
offset:偏移量
100:向后偏移100个字节
-100:向前偏移100个字节
whence:基点
SEEK_SET:文件开头
SEEK_END:文件末尾
SEEK_CUR:文件当前位置
返回值:
成功:0
失败:-1
例:
定位到文件末尾:fseek(fp, 0, SEEK_END);
定位到文件末尾的前一个字节:fseek(fp, -1, SEEK_END);
long ftell(FILE *stream);
返回值:当前文件指针的位置(大小)
void rewind(FILE *stream);
功能:文件指针返回到文件开头
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("./1.txt", "r+");
if (NULL == fp)
{
perror("fopen");
return -1;
}
int ret = fseek(fp, 0, SEEK_END); // 把指针移动到文件末尾
int n = ftell(fp); // 统计文件的大小,也就算统计文件的位置。返回字节数
printf("文件的大小(字节):%d \n", n); // 结果:文件大小
rewind(fp); // 把文件的指针返回到文件的开头
int m = ftell(fp);
printf("文件的大小(字节):%d \n", m); // 指针返回到文件开头再来看指针的位置。结果:0
return 0;
}
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:读取数据(可以读取二进制、字符数据)
参数:
ptr:内存地址 eg: char ptr[];
size:字节数
nmemb:块数
stream:流指针
返回值:
成功:块数
失败:-1
char buf[1000] = {0};
函数的用法(可用于读取普通数组或结构体数组):
fread(buf, 100, 10, fp); // 读取1000个字节的数据
fread(buf, 10, 100, fp);
fread(buf, 1, 1000, fp);
fread(buf, 1000, 1, fp);
fread(buf, 20, 50, fp);
.......
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("./1.txt", "rb"); // 二进制方式读取文件
if (NULL == fp)
{
perror("fopen");
return -1;
}
char buf[100] = {0};
int n = fread(buf, 100, 1, fp); // 读取文件到BUF
printf("%d \n", n);
printf("%s \n", buf);
fclose(fp);
return 0;
}
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:写入数据(可以写入二进制、字符数据)
参数:
ptr:内存地址 eg: char ptr[];
size:字节数
nmemb:块数
stream:流指针
返回值:
成功:块数
失败:-1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct A
{
int m;
float n;
char ch;
};
int main(int argc, const char *argv[])
{
// printf("%d\n", sizeof(struct A));
struct A a = {10, 3.14, 'b'};
struct A b;
printf("%d\n", sizeof(a));
FILE *fp = fopen("./1.txt", "wb+"); // 打开文件,注意这里的打开方式为读写,W后面有个b是说明二进制文件。
if (NULL == fp)
{
perror("fopen");
return -1;
}
// 结构体信息写入文件。
fwrite(&a, sizeof(struct A), 1, fp);
printf("write success!\n");
// 因为上面的写入函数执行后,就把文件的指针移位了,这里使用rewind函数使文件指针回到文件的开头。
rewind(fp);
// 如果不执行上一步操作的话,这里的fread就不会从文件开头读并写入到结构体b中。
fread(&b, sizeof(struct A), 1, fp);
// 打印结构体b的数据。
printf("%d %.2f %c\n", b.m, b.n, b.ch);
fclose(fp);
return 0;
}