IO文件
为什么要学习IO
公交车坠湖,飞机去哪里,黑匣子,黑匣子当中记录失事前所有的数据,
数据: (1).疲劳驾驶
(2).超速
(3).叉车失灵
等等.保存到硬盘当中.
内存:一般掉电就消失了
硬盘: 以文件的形式保存在硬盘中
Linux一切皆文件:
- 普通文件
d 目录文件
l 链接文件
s socket文件
p 管道文件
c 字符设备文件
b 块设备文件
标准IO和文件IO区别:
标准IO:
1.标准IO是由ANSIC(ANSI美国国家标准协会及国际标准化组织(ISO))标准定义
2.跨平台,既可以运行在windows下,也可以运行在Linux下
3.标准IO通过缓冲机制减少系统调用,实现更高的效率.
4.文件流,标准IO用结构体类型(FILE)来存放文件的相关信息,标准IO所有操作围绕FILE来进行
文件IO:
1.是POSIX(可移植操作系统接口)提供一组函数
2.不能跨平台,只能运行可移植操作系统中
3.非缓冲机制
4.文件描述符,(一个非负整数),没打开一个文件系统会自动分配一个文件描述符
系统调用
关于系统调用记住两点:
(1).有操作系统的情况下,应用程序要访问硬件不允许直接访问,必须通过操作系统提供的系统调用接口来完成.
(2).不同的操作系统提供的系统调用函数的不同的.
缓冲机制
什么是缓冲机制:
缓冲类型:
1.全缓冲
当流的缓冲区无数据或无空间时才执行实际的I/O操作
2.行缓冲
当输入和输出中遇到换行符’\n’时,进行I/O实际操作
3.无缓冲
打印错误信息,无缓冲,直接显示在终端上,数据直接写入文件,流不进行缓冲
标准IO:
标准IO用结构体类型(FILE)来存放文件的相关信息,标准IO所有操作围绕FILE来进行
文件流:文本流
二进制流
windows: 二进制流: 换行符------‘\n’
文本流 : 换行符-------‘\r’’\n’
Linux下:文本流和二进制流无区别:
文本流:
2047 —>‘2’ ‘0’ ‘4’ ‘7’ 00110010 00110000 00110100 00110111
二进制:
2047 ---->转换称为二进制 00000011 11111111
文件的打开和关闭
#include <stdio.h>
函数功能:打开文件
参数1:文件名 (可包含路径)
参数2:文件的打开方式:
r 以只读方式打开文件,文件不存在,则报错
r+ 以读写方式打开文件,文件不存在,则报错
w 以只写方式打开文件,文件不存在则新建,文件存在则清空文件中的内容
w+ 以读写方式打开文件,文件不存在则新建,文件存在则清空文件中的内容
a 以追加的方式打开文件,文件不存在则新建,文件存在则追加到文件的末尾
a+ 以读写的方式打开文件,文件不存在则新建,文件存在则追加到文件的末尾
返回值:成功返回文件指针FILE *,失败则返回NULL
FILE *fopen(const char *path, const char *mode);
函数功能:关闭文件
参数1:打开文件的指针
#include <stdio.h>
int fclose(FILE *fp);
文件的读取
按字符读取
char ch=’A’;
int a=65;
#include <stdio.h>
函数功能:从文件中获取一个字符,
参数:文件指针
返回值: char —>1个字节的int 失败,返回EOF,只能判断文本文档流,二进制流不能判断
int fgetc(FILE *stream);
模拟cat命令
#include <stdio.h>
函数功能:给文件写入一个字符
参数1:要写入的字符
参数2:文件指针
int fputc(int c, FILE *stream);
模拟cp命令
cp 1.txt 2.txt
1----------以只读方式打开文件1.txt(argv[1])给fr
2----------以只写方式打开文件2.txt(argv[2])给fw
3----------从fr中读取一个字符给ch,若不为EOF
4----------将ch写入到fw中去
5----------循环3,4直到ch==EOF结束
6----------关闭fr,fw
按行读取(只适合读写文本文件,二进制文件会有问题)
函数功能:读写一行字符串
读到’\n’或已读取size-1个字符时返回
参数1:字符串的首地址
参数2:读取size个字节
参数3:从哪个文件读取
char *fgets(char *s, int size, FILE *stream);
stdin ---->标准输入
stdout ---->标准输出
stderr ---->标准出错
gets(str) ----------------->fgets(strr,sizeof(str),stdin);
获取文本文档当中有多少行
参数1:你要写入空间的首地址
参数2:文件指针
int fputs(const char *s, FILE *stream);
按对象读取
参数1:数据的首地址
参数2:要写入的字节数
参数3:一次性写几个数据进去
参数4:写入的文件指针
返回值:成功返回具体写入了几个数据,失败则返回-1
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
#include <stdio.h>
参数1:空间的首地址
参数2:数据的字节数
参数3:一次性读取多少个字节
参数4:文件指针
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
=按格式化取
获得系统时间,写入到文件中去
#include <time.h>
//参数1:time_t *
这个函数会返回1970年到现在的秒数
如果t非空指针的话,这个函数也会将返回值存储到t指针所指的内存中
time_t time(time_t t);
函数功能:获得当地时间
参数:time_t *
返回值:struct tm *
struct tm {
int tm_sec; / seconds / 秒
int tm_min; / minutes / 分
int tm_hour; / hours / 时
int tm_mday; / day of the month / 日
int tm_mon; / month / 月[0-11]+1
int tm_year; / year / 年 —>1900到现在的年份
int tm_wday; / day of the week /
int tm_yday; / day in the year /
int tm_isdst; / daylight saving time */
};
struct tm *localtime(const time_t *timep);
#include <stdio.h>
int printf(const char *format, …);
参数1:文件指针
参数2:类似于printf()
int fprintf(FILE *stream, const char *format, …);
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
文件其他相关函数
1.判断是否到文件末尾
参数:文件指针
返回值:已到文件末尾返回非0,否则返回0
int feof(FILE *stream);
2.刷新缓冲区
#include <stdio.h>
int fflush(FILE *stream);
3.移动文件指针
#include <stdio.h>
参数1:文件指针
参数2:偏移量
参数3:从什么位置开始移动
int fseek(FILE *stream, long offset, int whence);
SEEK_SET, 从文件开头开始移动
SEEK_END, 从文件末尾开始移动
SEEK_CUR 从文件当前位置开始移动
4.获得文件指针的当前位置
long ftell(FILE *stream);
通过3(fseek)和4(ftell)可以获得文件的大小
//1.从文件末尾移动0个字节
//2.获得文件指针的位置
总结:
1,2021/06/17 17:21:48
2,2021/06/17 17:21:49
3,2021/06/17 17:21:50
4,2021/06/17 17:21:51
5,2021/06/17 17:21:52
6,2021/06/17 17:21:53
7,2021/06/18 08:35:53
8,2021/06/18 08:35:54
1.以a+方式打开文件1.txt(文件指针在文件末尾) fopen
2.将文件指针移动到文件开头 fseek
3.获得该文件有多少行 fgets
4.将行号,系统时间写入文件中 fprintf time localtime
5.手动刷新缓冲区 fflush
6.循环3,4
7.关闭文件 fclose
#include <stdio.h>
#include <string.h>
#include <time.h>
#define SIZE 20
//编写一子函数,获得该文件中有多少行
//参数1:打开的文件指针 FILE * fp
//返回值:行数 int
int filelength(FILE * fp);
int filelength(FILE * fp)
{
//1.将文件指针移动到文件开头
fseek(fp,0,SEEK_SET);
char str[SIZE]={'\0'};
int line=0;
while(1)
{
//1.清空字符数组
memset(str,'\0',sizeof(str));
//2.从文件指针中获得数据
fgets(str,SIZE,fp);
//3.判断最后一个字符是否为'\n'
if(feof(fp)) break;
if(str[strlen(str-1)]=='\n')
{
line++;
}
}
return line;
}
int main(int argc, const char *argv[])
{
//1.以a+方式打开文件1.txt (文件指针在文件末尾)
FILE * fp=NULL;
fp=fopen(argv[1],"a+");
if(NULL==fp)
{
perror("open error");
return -1;
}
//2.调用子函数获得文件的行数
int line=filelength(fp);
time_t t;
struct tm * pt=NULL;
while(1){
line++;
//3.获得系统时间
time(&t); //获得1970到现在的秒数
pt=localtime(&t);
fprintf(fp,"%d,%04d/%02d/%02d %02d:%02d:%02d\n",line,pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,pt->tm_hour,pt->tm_min,pt->tm_sec);
sleep(1);
//4.手动刷新缓冲区
fflush(fp);
}
//关闭文件
fclose(fp);
return 0;
}