【1】I/O
i:input 输入 从文件中输入内容到内存中
o:output 输出 从内存中将内容写道文件中
内存:掉电数据会丢失 RAM
实际磁盘内存(物理内存空间):掉电数据不会丢失 ROM
linux中文件类型七种:bcd-lsp
b: 块设备
c: 字符设备
d:目录文件
-:普通文件
l : 链接文件
s:套接字文件
p:管道文件
【2】标准IO
标准IO是指在C库中提供的一组专门用于输入输出的函数
标准I/O由ANSI C标准定义
不仅在UNIX系统,在很多操作系统上都实现了标准I/O
标准I/O通过缓冲机制减少系统调用次数,实现更高效率
标准I/O库的所有操作都是围绕流(stream)来进行的,
在标准I/O中,流用FILE *来描述。
标准IO默认打开了三个流:stdin、stdout、stderr
标准输入、标准输出、标准出错补充:系统调用(文件IO)
linux内核:
应用层: app shell命令
| |
| shell解析器 bash sh csh ksh
| |
| |
| c库
| |
-----------系统调用----------
内核
-----------------------------
硬件
系统调用:是内核向上提供的函数接口,不同的操作系统的内核,向上提供的函数接口是不同的。
(文件IO) ,没有缓冲机制。
c库:在系统调用前做了一个二次封装,是间接的进行了系统调用。(标准IO)
c库可以在不同的操作系统上使用。
char buf[1024];//是在使用读文件或写文件的时候开辟
//特点,一次性读满后,实际的读函数用多少,从这个缓存区中拿多少,直到缓存区的内容
//被读拿完,再次遇到读函数,才会进行第二次系统调用读满缓存区。
fread(8byte)--》c库 实际要用8byte
一次性读满buf
{
if(是linux)
read(buf=1024);
else if(是 windows)
Read(buf=1024);
else if( 是 mac)
_read();
}
【3】流(stream)和流指针(FILE *)
定义:所有的I/O操作仅是简单的从程序移进或者移出,
这种字节流,就称为流。
分类:文本流/二进制流。
流指针:FILE *
每个被打开的文件都在内存中开辟一个区域,
用来存放文件的有关信息,这些信息是保存在一个
结构体类型的变量中,该结构体类型是由系统定义的,
取名为FILE。
【4】缓存区的分类
1.全缓存:基于文件
刷新条件:
1)缓存满刷新
2)fflush强制刷新
3)正常结束(main:return 0;)
4)exit退出进程函数
2.行缓存:stdin、stdout
刷新条件:
1)缓存满刷新
2)‘\n’刷新
3)fflush强制刷新
4)正常结束(main:return 0;)
5)exit退出进程函数
exit(-1);
特殊情况:当遇到scanf等阻塞等待输入的函数,输出缓存区会刷新。
3.不缓存:stderr
char* _IO_buf_base;
//缓存去的起始地址
char* _IO_buf_end;
// 缓存区的截止地址
缓存区的截止地址-起始地址=缓存区大小
【5】标准io操作函数
1.fopen / fclose 打开/关闭文件
2.fgetc / fputc 一个字符的io
3.fgets / fputs 一行的io
4.fread / fwrite 直接io
man手册
man man 查看man手册功能
1 Executable programs or shell commands 查看shell命令
2 System calls (functions provided by the kernel) 查看内核向上提供的函数接口(系统调用函数)
3 Library calls (functions within program libraries) c库函数
1.fopen
FILE *fopen(const char *path, const char *mode);
功能:打开指定路径下的文件
参数:
path:文件的路径
mode:打开文件的方式
r:只读、文件指针定位到文件的开头
r+:可读可写、文件指针定位到文件的开头
w: 只写、文件存在清空、不存在创建、文件指针定位到文件开头
w+:可读可写、文件存在清空、不存在创建、文件指针定位到文件开头
a:追加(只写)、文件存在追加、不存在创建。追加到文件结尾
a+:追加(可读可写),写在结尾,读在文件开头。文件不存在创建。
返回值:
成功:文件流指针
失败:NULL 更新errno
//一个文件可以被打开多次,每次返回的流指针都是不同的。
2.perror
void perror(const char *s);
功能:根据errno值打印对应的错误信息
参数:s:提示的字符串
返回值:无
#include <string.h>
char *strerror(int errnum);
功能:根据errno值打印对应的错误信息
参数:errnum--》errno值 #include <errno.h>
返回值:
成功:错误信息字符串的首地址
失败:NULL
3.fclose
int fclose(FILE *stream);
功能:关闭文件
返回值:成功0 失败EOF(-1)
练习:验证一个进程中最多能打开多少个文件? 1024
一个进程中打开的文件个数是固定的,属于有限资源,用完后需要释放。
4.fgetc
int fgetc(FILE *stream);
功能:从指定的文件中读取一个字符
参数:
stream 文件流指针
返回值:
成功:读到字符的ascii值
失败或读到文件结尾:EOF
5.fputc
int fputc(int c, FILE *stream);
功能:向指定的文件中写入一个字符
参数:
c:要写入字符
stream:文件流指针
返回值:
成功:字符的ascii值
失败:EOF
6.fgets
char *fgets(char *s, int size, FILE *stream);
功能:从指定的位置读一串字符
参数:
s:读到字符串存放的位置
size:期待读字符的个数
实际读到的个数是size-1个,留一个位置进行补‘\0’
遇到‘\n’,不再往后读字符
stream:文件流指针
返回值:
成功 :返回字符串存放的地址
失败或读到文件结尾:NULL
7.fputs
int fputs(const char *s, FILE *stream);
功能:将字符串输出到指定文件中
参数:s:输出内容
stream:文件流指针
返回值:成功:输出字符的个数
失败:EOF
练习:用fgets实现wc -l file 的功能
**** buf:****\0 buf:\n\0
******* buf:****\0 buf:***\n\0
****** buf:****\0 buf:**\n\0
while( fgets(buf,5,fd) != NULL)
{
if(buf[strlen(buf)-1]=='\n')
n++;
}
补充:对于main函数的参数
argc:命令行参数的个数
argv: ---》char *argv[] 保存的是命令行参数的内容 ./a.out hello world
int a=10,b=20,c=30;
int *arr[3]={&a,&b,&c};//指针数据,数组,数组的元素是指针
char *ch[3]={"hello","world","welcome"};//char *p="hello";
==> ch[0]="hello"; ch[1]="world"
printf("%s\n",ch[0]);
作业:
练习:用fgets和fputs实现cp的功能
/*************************************************************************
> File Name: cpByC.c
> Created Time: Sun 15 Aug 2021 09:14:10 AM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp1;
char str[50];
printf("plz input filename as source\n");
scanf("%s", str);
if ((fp1 = fopen(str, "r")) == NULL) {
perror("fopen");
exit(1);
}
char str2[50];
printf("plz input filename as target\n");
scanf("%s", str2);
FILE *fp2;
if ((fp2 = fopen(str2, "w+")) == NULL) {
perror("fopen");
exit(1);
}
while (fgets(str,50, fp1) != NULL) {
fputs(str, fp2);
}
return 0;
}
验证全缓存的刷新条件,同时计算全缓存缓存的大小。
/*************************************************************************
> File Name: fullBuffer.c
> Created Time: Sun 15 Aug 2021 09:50:04 AM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
FILE *fp;
if((fp = fopen("20.txt", "w")) != NULL) {
fprintf(fp,"%ld\n",fp->_IO_buf_end - fp->_IO_buf_base);
printf("full buffer size: %ld\n",fp->_IO_buf_end - fp->_IO_buf_base);
}
return 0;
}
- 题目要求:编程读写一个文件test.txt,每隔1秒向文件中写入一行数据,类似这样:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
该程序应该无限循环,直到按Ctrl-C中断程序。
再次启动程序写文件时可以追加到原文件之后,并且序号能够接续上次的序号,比如:
1, 2007-7-30 15:16:42
2, 2007-7-30 15:16:43
3, 2007-7-30 15:19:02
4, 2007-7-30 15:19:03
5, 2007-7-30 15:19:04
/*************************************************************************
> File Name: time.c
> Created Time: Sat 14 Aug 2021 05:13:43 PM CST
> Author: noah
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *fp;
if ((fp = fopen("time.txt", "a+")) == NULL) {
perror("fopen");
exit(1);
}
char ch;
int n = 1;
char str[50];
FILE *fp2;
fp2 = fopen("time.txt", "r");
while ((fgets(str, 50, fp2)) != NULL) {
n++;
}
fclose(fp2);
while (1) {
time_t curTime = time(NULL);
char *curDate = ctime(&curTime);
printf("%d.", n);
printf(curDate);
fprintf(fp, "%d.", n++);
fputs(curDate, fp);
fflush(fp);
sleep(1);
}
fclose(fp);
return 0;
}
补充函数:
-
fprintf
int fprintf(FILE *stream, const char *format, ...);
功能:以指定的格式向文件中输出 -
sprintf
int sprintf(char *str, const char *format, ...);
功能:以指定的格式将内容存放到数组中 str -
time
#include <time.h>
time_t time(time_t *t);
功能:获取系统从1970-01-01 00:00:00到当前时间的秒数
参数:
t:获取到的秒数
返回值:
成功:获取到的秒数
失败:-1 更新errno -
localtime
struct tm *localtime(const time_t *timep);
功能:将1970-0 1-01 00:00:00到现在的秒数转换为年月日,时分秒
参数:
timep
:时间(time获取的秒数)
返回值:
成功:返回保存时间结构的地址
失败:NULL
struct tm {
int tm_sec; /* 秒 */
int tm_min; /* 分*/
int tm_hour; /* 小时 */
int tm_mday; /* 一个月的某一天 */
int tm_mon; /* 月 */
int tm_year; /* 年 */
int tm_wday; /* 一周的某一天 */
int tm_yday; /*一年中的某一天 */
int tm_isdst; /* daylight saving time */
};
ctime
char *ctime(const time_t *timer)
C 库函数char *ctime(const time_t *timer)
返回一个表示当地时间的字符串,当地时间是基于参数timer
。
返回的字符串格式如下: Www Mmm dd hh:mm:ss yyyy 其中,Www 表示星期几,Mmm 是以字母表示的月份,dd 表示一月中的第几天,hh:mm:ss 表示时间,yyyy 表示年份。
参数
timer – 这是指向 time_t 对象的指针,该对象包含了一个日历时间。
返回值
该函数返回一个 C 字符串,该字符串包含了可读格式的日期和时间信息。