- 基础知识:
内核:负责管理一部分硬件资源
系统调用:内核提供给用户访问其内部操作的一些函数接口
IO的分类
标准IO
POSIX标准:可移植操作系统接口规范
POSIX 标准 : 规定 函数功能, 返回值,函数的参
文件IO(系统调用)
main.c
main()
{
fread();
fwrite();
}
-------------------------------------------------------
标准IO printf scanf()//不同的系统有不同的输入输出函数,导致程序可移植性差,为此标准I/O应运而生(采取POSIX标准)
标准IO的
本质: 是对系统调用的再次封装
作用:
增强了代码的可移植性,复用性
提高了效率。
标准IO增加了一个【相当重要:缓冲机制】
系统调用:(文件IO)
不带缓冲区
操作系统直接提供的函数接口
调用 系统调用 是很耗费资源的
`` **建议: 使用标准IO读写文件**``
两类函数
标准IO:标准C库里提供的
只要开发环境中安装了标准C库就可以使用 - 可移植 性好
设有缓冲区,每次对文件操作的时候先操作缓冲区,必要时再通过
系统调用访问真实的文件
文件IO:操作系统提供
需要操作系统兼容和POSIX标准
每次对文件操作时都需要通过系统调用访问真实的 文件 - 系统开销比较大
缓冲区
是系统预留的一部分特定的内存,用来缓存输入和输出的数据
缓冲区的类型
全缓冲
当填满缓冲区,再进行实际的IO操作
用标准IO打开文件时
行缓冲
当遇到换行符,再进行实际的IO操作
scanf, printf
无缓冲
直接进行实际的IO操作
perror
- 标准IO - 设有缓冲区
操作对象:流 - FILE
文件一般操作步骤: 打开文件 - 读写操作 - 关闭文件
man 3 C库里的函数
这里函数太多 及不知就man 这是真理 使用多了之后自然就记住了
标准IO系统过有三种预定义的流在stdio.h中预定的
标准输入流 stdin
标准输出流 stdout
标准出错流 stderr
1)打开文件
FILE *fopen(const char *path, const char *mode);
参数1:打开的文件的路径
参数2:打开文件的方式
r :只读,要求文件要存在
r+:可读可写,要求文件要存在
w :只写,不存在创建,存在会清空
w+:可读可写,不存在创建,存在会清空
a :追加的方式打开(只写),不存在创建,存在在末尾追加
a+:追加的方式打开(可读可写),不存在创建,存在在末尾追加
返回值:成功 - 流指针
失败 - NULL,设置错误码
1)文件的读操作
【1】按照字符读取
功能:从指定流中读取一个字符
int fgetc(FILE *stream);
int getc(FILE *stream);
参数:流指针
返回值:成功 - 读取到的字符
失败或者读到文件尾 - EOF
int getchar(void); === fgetc(stdin);
练习:使用fgetc实现读取文件中所用内容
#include <stdio.h>
int main( int argc, char*argc[])
{
int ret;
FILE *fp = NULL;
fopen(argv[1],"r")//从终端中获取要用只读方式打开的文件
if(fp == NULL)
{
perror("open file failed\n")//打开文件失败打印失败信息
return -1;//结束程序的执行
}
while(1)//不断地在文件中一个字符一个字符的读取数据
{
ret = fget(fp);
if(ret == EOF)break;//读取结束跳出循环
printf("%c",ret);//不断地将读取到数据打印在终端
}
return 0;
}
【2】按行读取
char *fgets(char *s, int size, FILE *stream);
参数1:用来保存读取到内容
参数2:读取的大小 - 字节 ,一行有n的字符
size <= n - size-1个字节
size > n - n个字节
参数3:流指针
返回值:成功 - s
失败/读到文件尾 - NULL
char *gets(char *s); == fgets(s, size, stdin);
注意:gets函数 换行符不作为有效字符读取
练习:fgets统计文件中有多少行
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
int len =0;
char buf[10] = {0};
char *p =NULL;
FILE* fp = NULL;
fp = fopen(argv[1],"r");
if(fp == NULL)
{
perror("open file failed\n")//打开文件失败打印失败信息
return -1;//结束程序的执行
}
while(1)//逐行的循环读取数据
{
p =fgets(buf,10,fp);
if(p = NULL)break;//此时文件已经读完,跳出循环
if(buf[strlen(buf)-1] == '\n')//字符串的最后一位位‘\0’,所以所以换行符‘\n’在最后一位
len++;//遇见'\n'行数+1
bzero(buf, sizeof(buf));//每次使用完数据要把数据清空,防止下次使用出现错误的数据
printf("len: %d\n",len);
}
return 0;
}
【3】按照指定大小读取
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数1:存放读取到的内容的首地址
参数2:读取的单位大小
参数3:读取的个数
参数4:流指针
返回值:成功 - 实际读取的字节数
读到文件尾 - 0
2)文件的操作
【1】按字符写入
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
功能:向指定流中写入一个字符
参数1:写入的字符
参数2:流指针
返回值:成功 - 写入的字符
失败 - EOF
int putchar(int c); === fputc(c, stdout);
向标准输出流中写入一个字符
练习:使用fgetc和fputc编写一个程序,实现cp功能
#include<stdio.h>
int main(int argc, char *argv[])
{
int ret;
FILE *fp1 = NULL;//要拷贝的源文件的文件描述符
FILE *fp2 = NULL;//要拷贝的目标文件的文件描述符
if (argc < 3)
{
printf("输入的参数有错误");
return -1;
}
fp1 = fopen(argv[1],"r");
fp2 = fopen(argv[2],"w");
if((fp1 == NULL)||(fp2 == NULL))
{
perroe("打开文件失败");
}
while(1)
{
ret = fgetc(fp1);
if(ret == EOF)break;
fputc(ret,fp2);
}
return 0;
}
【2】按行写入
int fputs(const char *s, FILE *stream);
int puts(const char *s); === fputs(s, stdout);
参数1:要写入的数据的首地址
参数2:流指针
返回值:成功 - 非0
失败 - EOF
练习:使用fgets和fputs编写一个程序,实现cp功能
# include <stdio.h>
# include <string.h>
int mian(int argc,char * argv[])
{
char buf[10] = {10};
char *p = NULL;
FILE *fp1 = NULL;
FILE* fp2 = NULL;
if(argc < 3)
{
printf("输入参数错误");
return -1;
}
fp1 = fopen(argv[1], "r");
fp2 = fopen(argv[2], "w");
if((fp1 == NULL)||(fp2 == NULL))
{
perror("打开文件失败");
return -1;
}
while(1)
{
p = fgets(buf,10,fp1);
if(p == NULL)break;
fputs(buf,fp2);
memset(buf,0,sizeof(buf));
}
return 0;
}
【3】按指定大小写入
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数1:存放写入的数据的首地址
参数2:写入数据的单位大小
参数3:写入的个数
参数4:写入的文件的流指针
返回值:成功 - 写入的字节数
失败 - 0
ret = fwrite(buf, 1, sizeof(buf), fp);
- 扩展学习
【1】 出错处理
errno - 是一个全局变量 #include <errno.h>
void perror(const char *s);
功能:输出错误信息
参数:自定义的字符串 - 提示信息
【2】关闭文件
int fclose(FILE *fp);
返回值:成功 - 0
失败 - EOF
fclose(fp);
【3】修改文件指针位置
int fseek(FILE *stream, long offset, int whence);
参数1:流指针
参数2:偏移量
参数3:基准
SEEK_SET:文件起始位置
SEEK_CUR:文件当前位置
SEEK_END:文件的结束位置
返回值:成功 - 0
失败 - -1
【4】清空指定空间的数据
void bzero(void *s, size_t n); === memset(s, 0, n);
功能:给某个空间里的内容清0
参数1:要清0的空间的首地址
参数2:要清的空间的大小 - 字节
void *memset(void *s, int c, size_t n);
功能:给某块空间填充某个内容
参数1:要填充的空间的首地址
参数2:要填充的内容
参数3:要填充的空间的大小
返回值: s