用户在应用开发过程中会经常需要访问文件。Linux下读写文件的方式有两大类:标准IO和文件IO。其中标准IO是最常用,也是最基本的内容,可以说标准IO是文件IO的再封装。
标准IO
一、标准IO
文件类型
普通文件 -
目录文件 d
管道文件 p
链接文件 l
字符设备文件 c
块设备文件 b
套接字文件 s
注意: 不同操作系统适用的文件类型不同
1. 标准IO
标准IO遵循ANSI C标准,标准IO实际是调用标准C库中的函数
特点:
标准IO利用缓冲机制,减少系统调用的次数,从而提高程序运行的效率。
标准IO - 高级IO
文件IO - 低级IO
标准IO是在文件IO的基础上做的一次再封装
标准IO一般用于操作普通文件
2. 流
数据仅是简单地从文件进行流入、流出,称这种现象为流。
流在文件中用FILE结构体描述。
/* FILE结构体的部分定义 */
struct _IO_FILE
{
char *_IO_buf_base; /* Start of reserve area. 缓冲区起始位置*/
char *_IO_buf_end; /* End of reserve area. */
int _fileno; /* 文件描述符 */
......
}
//在一个程序中,一个FILE结构体对应一个文件
3. 流的类型
流的类型有两种:文本流、二进制流
1)文本流
将数据转换为对应的ASCII码再进行存取
2)二进制流
将数据转换为二进制再进行存取
文本流和二进制流处理换行符方式不同:
在linux中,没有对文本流和二进制流做区分,换行符不做任何处理。
文本流:
将换行符转换为 ‘\r’‘\n’
二进制流:
换行符不做处理 ‘\n’
4. 缓冲区类型
1)全缓冲
打开一个文件时,默认使用全缓冲。
当缓冲区满或者空时,才进行实际的IO操作
2)行缓冲
当输入输出跟终端相关时,使用行缓冲。
当缓冲区满或者遇到换行符时才进行实际的IO操作
3)无缓冲
跟错误输出相关时使用无缓冲
三个特殊流(默认打开):
标准输入流 - stdin - 键盘
标准输出流 - stdout - 终端
标准错误流 - stderr
三、标准IO相关库函数
fopen()/fclose() 打开/关闭文件
fgetc()/fputc() 按字节读/写文件
fgets()/fputs() 按行读/写文件
fread()/fwrite() 按对象(固定大小)读/写文件
ftell()/fseek()/rewind() 定位文件(文件指针位置)
fflush() 刷新流(强制刷新缓冲区)
feof() 判断错误流
1) 打开文件 fopen()
FILE *fp = fopen("1.c","r");
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
返回值:
成功返回对应的文件的流指针,失败返回NULL,并设置错误号(errno)
errno: 当前系统中最后一个错误的编号
------------------------------------------------------------
#include <string.h>
char *strerror(int errnum);
参数 errnum 错误号
返回值 成功返回错误原因
------------------------------------------------------------
#include <stdio.h>
void perror(const char *s);
------------------------------------------------------------
参数:
pathname: 打开文件的文件名(包含路径)
mode : 打开文件的方式
r 以只读方式打开文件,文件必须要存在
r+ 以读写方式打开文件,文件必须要存在
w 以只写方式打开文件,文件不存在则先创建再打开
w+ 以读写方式打开文件,文件不存在则先创建再打开
a 以只写[追加]方式打开文件,文件不存在则先创建再打开
a+ 以读写[追加]方式打开文件,文件不存在则先创建再打开
2) 关闭文件 fclose()
fclose(fp);
#include <stdio.h>
int fclose(FILE *stream);
参数:
stream: 关闭文件对应的流指针
返回值:
成功返回0, 失败返回 -1;
3) 按字节读/写文件 fgetc()/fputc()
FILE *fp = fopen("1.txt","r");
if(NULL == fp){
perror("open 1.txt");
return -1;
}
char c = fgetc(fp);
fputc(c,fp);
fclose(fp);
#include <stdio.h>
int fgetc(FILE *stream);
参数:
stream: 流指针
返回值:
成功返回读取的字符, 失败返回 -1;
读到文件末尾返回 -1;
#include <stdio.h>
int fputc(int c,FILE *stream);
参数:
c: 输入的字符
stream: 流指针
返回值:
成功返回写入的字符, 失败返回 -1;
/*
练习:
用fgetc()和fputc()完成文件的复制
终端输入命令:
./a.out src.txt dest.txt
*/
#include <stdio.h>
int main(int argc,char *argv[])
{
if(argc != 3){
printf("Usage:%s <src filename> <dest filename>\n",argv[0]);
return -1;
}
FILE *fp1 = fopen(argv[1],"r");
if(NULL == fp1){
perror(argv[1]);
return -1;
}
FILE *fp2 = fopen(argv[2],"a+");
if(NULL == fp2){
perror(argv[2]);
return -1;
}
char c;
while((c = fgetc(fp1)) != EOF){
fputc(c,fp2);
}
fclose(fp1);
fclose(fp2);
return 0;
}
4) 按行读写 fgets()/fputs()
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
参数:
s: 字符串首地址
size: 请求读取数据的最大长度
stream: 流指针
返回值:
成功返回得到字符串的首地址, 失败返回NULL;
注意:① 当读取内容为换行符,读取结束
② 最大读取内容为 size-1; 因为size位置要为'\0'
#include <stdio.h>
char *fputs(char *s,FILE *stream);
5) 按对象读写 fread()/fwrite()
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值:
成功返回读到的对象个数, 失败返回 0;
参数:
ptr: 存放字符串的首地址
size: 对象大小
nmemb: 对象个数
stream: 流指针
#include <stdio.h>
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
返回值:
成功返回写入的对象个数, 失败返回 0;
参数:
ptr: 存放字符串的首地址
size: 对象大小
nmemb: 对象个数
stream: 流指针
//上文中 用fgetc()/fputc() 复制文件的改写
int ret;
char buf[64] = {0};
while((ret = fread(buf, sizeof(char), 1, fp1)) != 0){
fwrite(buf,sizeof(char),1,fp2);
}
6) 刷新流 fflush()
#include <stdio.h>
int fflush(FILE *stream);
参数:
stream: 流指针
返回值:
成功返回 0,失败返回 -1;
7) 定位文件 ftell() / fseek() / rewind()
#include <stdio.h>
long ftell(FILE *stream);
功能:
返回文件指针相对于文件开头的偏移量
参数:
stream: 流指针
返回值:
成功返回文件指针相对于文件开头的偏移量,失败返回 -1;
int fseek(FILE *stream, long offset, int whence);
功能:
将文件指针定位到offset+whence位置
参数:
stream: 流指针
offset: 偏移量(可正可负)
whence: 基准点
SEEK_SET: 将文件指针定位在文件开头
SEEK_CUR 将文件指针定位在当前位置
SEEK_END 将文件指针定位在文件末尾
返回值:
成功返回0, 失败返回 -1;
void rewind(FILE *stream);
功能:
将文件指针定位到文件开头
8) 判断错误流 feof()
#include <stdio.h>
int feof(FILE *stream);
返回值:
1 表示流访问结束
0 表示错误返回
9) fprintf() / sprintf()
#include <stdio.h>
//格式化输出到流
int fprintf(FILE *stream,const char *format,...);
//格式化输出到str指向的字符串
int sprintf(char *str,const char *format,...);