标准IO和文件IO

标准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_tunsigned 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值