文章目录
标准IO
标准 I/O:是高级 I/O 操作,基于流(FILE*)进行操作,提供了缓冲机制,减少直接系统调用的次数,提高效率,包含以下函数
fopen
fopen()函数原型
FILE *fopen(const char *path, const char *mode);
path:文件路径
mode:打开模式,取值如下
模式字符串 | 含义 |
---|---|
" r " 或 " rb " | 以只读方式打开文件,文件必须存在。 |
" r+ " 或 " r + b " | 以读写方式打开文件,文件必须存在。 |
" w " 或 " wb " | 以只写方式打开文件,若文件存在则文件长度清为0。若文件不存在则创建。 |
" w+ " 或 " w + b " | 以读写方式打开文件,其他同”w”。 |
" a " 或 " ab " | 以只写方式打开文件,若文件不存在则创建;向文件写入的数据被追加到文件末尾。 |
" a+ " 或 " a + b " | 以读写方式打开文件。其他同”a” |
getc、putc
getc()函数原型:
int getc(FILE *stream);
该函数从stream指定的文件中读取一个字符,并返回该字符的ASCII码,(可以用一个char类型数据接收该返回值)。
putc()函数原型:
int putc(int c, FILE *stream);
c:要写入的字符
stream:要写入的文件流指针
fclose
fclose()函数原型:
int fclose(FILE *fp);
fclose(fp) 用于关闭fp指定的文件。关闭成功返回0,否则返回EOF。值得注意的是,对于较为正式的程序,应该检查是否成功关闭文件,如果磁盘已满。移动硬盘被移除或者出现I/O错误,都会导致fclose()函数失败。
fprintf、fscanf
函数原型:
int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
文件I/O函数 fprintf() 和 fscanf() 的工作方式和 printf() 、scanf() 类似,区别在于前者需要用第一个参数指定待处理的的文件。
fgets、fputs
函数原型:
char *fgets(char *s, int size, FILE *stream);
s:输入位置缓冲区
size:输入字节数
stream:输入文件流指针
例如定义一个字符串:
char buf[15];
以下代码表示将fp指定的文件中的前5个字符读取到字符串buf中:
fgets(buf,5,fp);
值得注意的是,fgets() 实际读取了fp文件中前size-1个字符,并在结尾加上’ \0 '构成字符串,然后放入buf中,共占5个字节。代码如下:
1、现在fgets.txt文件中写入hello world文本
然后将fgets.txt文本中的前5个字符读取到buf中去:
FILE* fp;
fp = fopen("fgets.txt","r");
if(fp == NULL){
perror("fopen");
return 0;
}
char buf[15];
fgets(buf,5,fp);
puts(buf);
return 0;
执行结果如下:
hell
至于为什么是这样的结果,是因为fegts()读取输入直到第一个换行符后面,或读到文件末尾,或者读取size-1个字符,然后,fgets()在末尾添加一个空字符使之成为一个字符串。字符串的大小是其字符数加上一个空字符。如果fgets()在读取到字符上限前已经读完一整行,它会把表示行结尾的换行符放在空字符前面。fgets()函数在遇到EOF时返回NULL,可以利用这一机制检查文件是否达到末尾。
fseek、ftell
函数原型:
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
fseek() 函数用于移动文件指针,将文件指针跳转到指定位置
第二个参数offset是文件指针偏移量,也就是相对于打开文件时指针位置的偏移量,offset的值可正可负,正值表示向后移动,负值表示向前移动,0表示不移动。(这里规定左为前,右为后)
第三个参数表示模式,用来确定移动前指针的位置,取值如下:
模式 | 偏移起始点 |
---|---|
SEEK_SET | 文件开始处 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件末尾 |
如果一切正常,那么 fseek() 返回0,如果出现错误,如试图移动的距离超过文件的范围,返回-1;
ftell() 返回值是long类型,它返回的是文件指针距离文件开始处的字节数。
以下代码用来测试fseek()和ftell()函数:
先在1.txt文件中写入文本:
#include<stdio.h>
int main(int argc, const char *argv[])
{
FILE* fp;
char ch;
long int i;
fp = fopen("1.txt","r+");
if(fp == NULL){
perror("fopen");
return 0;
}
fseek(fp,8,SEEK_SET); //将文件指针向后移动8个字节的位置,此时指针在o的后面,r的前面
ch = fgetc(fp); //获取的是指针后面的第一个字符,然后指针向后移动一个字节
i = ftell(fp); //此时指针位于r的后面
printf("ch = %c\n",ch);
printf("i = %ld\n",i);
close(fp);
return 0;
}
输出结果为:
ch = r
i = 9
fflush
函数原型:
int fflush(FILE *stream);
fflush()函数用来刷新缓冲区,如
fflush(stream);刷新缓冲区,并将缓冲区内容输出到stream文件中去
fwrite、fread
函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
这个两个函数既能读写文本文件,也能读写二进制文件,size_t 是 unsigned int 类型,ptr是被操作数据的地址,size是被操作数据块的大小,以字节为单位,nmemb表示数据块个数,stream表示被操作文件。
例如:用 fwrite() 向一个二进制类型文件中输入一个学生的结构体信息:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student {
char name[15];
int age;
char gender[8];
};
int main(int argc, const char *argv[])
{
FILE* fp;
struct student stu1;
fp = fopen("1.bin","w");
strcpy(stu1.name,"zhangsan");
stu1.age = 25;
strcpy(stu1.gender,"male");
if(fp == NULL){
perror("fopen");
return 0;
}
fwrite(&stu1,sizeof(stu1),1,fp);
fclose(fp);
return 0;
}
该程序向1.bin文件输入一个
name : zhangsan
age : 25
gender : male
的学生信息
程序运行后,1.bin文件中出现以下信息:
之所以是乱码,是因为文件是以二进制 (.bin) 格式保存的,但是文件内容已经正确保存,接下来读取此文件:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student {
char name[15];
int age;
char gender[8];
};
int main(int argc, const char *argv[])
{
FILE* fp;
struct student stu2;
fp = fopen("1.bin","r");
if(fp == NULL){
perror("fopen");
return 0;
}
fread(&stu2,sizeof(stu2),1,fp);
printf("name:%s\nage:%d\ngender:%s\n",stu2.name,stu2.age,stu2.gender);
close(fp);
return 0;
}
运行结果如下:
name:zhangsan
age:25
gender:male
sprintf、fprintf
函数原型
int sprintf(char *str, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
这两个是printf函数家族中的格式化输出函数,sprinf将内容输出到str字符串中,如下图将字符串str2中的内容输出到字符串str中
#include<stdio.h>
int main(int argc, const char *argv[])
{
char str[100];
char str2[100]="hello world";
sprintf(str,"%s",str2);
printf("%s\n",str);
return 0;
}
运行结果如下
fprintf则是将内容输出到文件流指针*stream中去。如下图,将字符串hello world输出到文件1.txt中:
#include<stdio.h>
int main(int argc, const char *argv[])
{
FILE *fp;
char str[100]="hello world";
fp=fopen("1.txt","r+");
if(fp==NULL){
perror("fopen");
return 0;
}
fprintf(fp,"%s",str);
fclose(fp);
return 0;
}
打开1.txt文件后显示如下内容:
文件IO
文件io定义:
posix(可移植操作系统接口)定义的一组函数
不提供缓冲机制,每次读写操作都引起系统调用
核心概念是文件描述符
访问各种类型文件
Linux下, 标准IO基于文件IO实现
open
打开文件
int open(const char *pathname, int flags); //文件已存在,仅打开文件
int open(const char *pathname, int flags, mode_t mode); //文件不存在,打开同时创建文件
pathname:文件路径
flags:文件打开方式,从以下取值
O_RDONLY: 只读方式打开文件
O_WRONLY: 可写方式打开文件
O_RDWR: 读写方式打开文件 //这三个互斥,相互之间不能进行或运算
O_CREAT: 如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限
O_EXCL: 如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在
O_NOCTTY: 使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。
O_TRUNC: 如文件已经存在,那么打开文件时先删除文件中原有数据。
O_APPEND: 以添加方式打开文件,所有对文件的写操作都在文件的末尾进行。
mode:被打开文件的存取权限,为8进制制表符,(每个文件有默认权限umaks(0002),
因此实际权限是 mode - umaks = 0666 - 0002 = 0664)
注:open能打开设备文件,但是不能创建设备文件(创建设备文件用mknode)
close
关闭文件
int close(int fd);
read
读文件
ssize_t read(int fd, void *buf, size_t count);
fd:要读取的文件流指针
buf:存放读取内容的缓冲区
count:读取字节数
成功时返回实际读取的字节数;出错时返回EOF
读到文件末尾时返回0
buf是接收数据的缓冲区
count不应超过buf大小
write
写入文件
ssize_t write(int fd, void *buf, size_t count);
fd:要写入的文件流指针
buf:存放写入内容的缓冲区
count:写入字节数
成功时返回实际写入的字节数;出错时返回EOF
buf是发送数据的缓冲区
count不应超过buf大小
lseek
定位文件指针
off_t lseek(int fd, off_t offset, int whence);
fd:文件流指针
offset:指针偏移量,左负右正
whence:起始位置(设置从哪开始偏移),从以下取值
SEEK_SET 文件开始处
SEEK_CUR 当前位置
SEEK_END 文件末尾
成功时返回当前的文件读写位置;出错时返回EOF