2019年7月26日星期五(文件IO)

一. 标准IO

1. 标准IO函数有什么特点?

标准IO函数都是封装在一个库中,这个库就是标准C库,标准C库头文件都是#include <stdio.h>,所以标准IO函数的头文件都是#include <stdio.h>,而且标准IO处理方式与系统IO不一样,读取/写入数据时,都有缓冲区。

2. 系统IO与标准IO作用对象?

系统IO对象  -> 硬件设备文件,例如: 访问LCD液晶,触摸屏,红外传感器,温湿度传感器、超声波传感器

标准IO对象  -> 普通文件,例如: 访问1.txt,2.jpg,3.mp3...

二.如何使用标准IO来处理文件?

1. 访问文件?  -> fopen()  -> man 3 fopen

#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

path: 需要访问的文件的路径

mode: 操作文件的权限

r      Open text file for reading.  The stream is positioned at the beginning of the file.

//以只读方式打开文件,文件的定位在文件的开头!   O_RDONLY

r+     Open for reading and writing.  The stream is positioned at the beginning of the file.

//以读写方式打开文件,文件的定位在文件的开头!   O_RDWR

w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.  //以只写方式打开文件,如果文件不存在则创建,存放则清空,文件的定位在文件开头  O_WRONLY|O_CREAT|O_TRUNC

w+     Open  for  reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning of the file.

//以读写方式打开文件,如果文件不存在则创建,存放则清空,文件的定位在文件开头   O_RDWR|O_CREAT|O_TRUNC

a      Open for appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.

//以只写方式打开文件,以追加方式写入文件,文件不存在则创建,文件的定位文件的末尾。  O_WRONLY|O_APPEND|O_CREAT

a+     Open for reading and appending (writing at end of file).  The file is created if it does not exist.  The initial file position for reading is at the beginning of the file, but output is always appended to the end of the file.  //以读写方式打开文件,以追加方式写入文件,不存在则创建,如果是读操作,则从文件定位在文件开头,如果是写操作,则文件的定位在末尾。

返回值:

成功:文件指针

失败:NULL

2. 关闭文件?  -> fclose()  -> man 3 fclose

fclose - close a stream

#include <stdio.h>

int fclose(FILE *fp);

fp: 需要关闭的文件流指针

返回值:

成功:0

失败:EOF

#ifndef EOF

# define EOF (-1)

#endif

三. 关于默认打开的三个文件的文件指针。

头文件路径: /usr/include/unistd.h

文件描述符:

#define  STDIN_FILENO      0     -> 标准输入的文件描述符

#define  STDOUT_FILENO  1     -> 标准输出的文件描述符

#define  STDERR_FILENO   2     -> 标准出错的文件描述符

文件指针:

extern struct _IO_FILE *stdin;             -> 标准输入的文件指针

extern struct _IO_FILE *stdout;           -> 标准输出的文件指针

extern struct _IO_FILE *stderr;            -> 标准出错的文件指针

#define stdin stdin

#define stdout stdout

#define stderr stderr

===========================================================

总结:

文件描述符                 文件指针

标准输入        STDIN_FILENO          stdin

标准输出        STDOUT_FILENO           stdout

标准出错           STDERR_FILENO            stderr

练习1:测试fopen("w")中会不会创建,并关闭文件。

#include <stdio.h>

int main()

{

FILE *fp = NULL;

fp = fopen("test.txt","w");

if(fp == NULL)

printf("fopen error!\n");

fclose(fp);

return 0;

}

四. 关于标准IO读写操作。

1. 读取文件?  ->  fread()  -> man 3 fread

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

ptr:数据缓冲区

size: 每一个块的字节数

nmemb: 读取的块数

stream:文件流指针

返回值:

成功: 已经读取到的块数。

失败: 0

文件: 30                          24                 28

3  10   -> 3      3   10  -> 2      3   10 -> 2

2  15   -> 2      2   15  -> 1      2   15 -> 1

5  10   -> 3      5   10  -> 2      5   10 -> 2

2. 写入文件?  -> fwrite()  -> man 3 fwrite

#include <stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

ptr:数据缓冲区

size: 每一个块的字节数

nmemb: 写入的块数

stream:文件流指针

返回值:

成功: 已经写入的块数。

失败: 0

练习2: 验证读写返回值。

#include <stdio.h>

int main()

{

FILE *fp = NULL;

//char buf[50] = {0};

int n;

char wbuf[20] = "hello";

fp = fopen("test.txt","r+");  //17

if(fp == NULL)

printf("fopen error!\n");

//n = fread(buf,10,2,fp);

//printf("n = %d\n",n);//1

n = fwrite(wbuf,6,3,fp);

printf("n = %d\n",n);

fclose(fp);

return 0;

}

五. 关于标准IO文件指针定位函数

1. 重新定位文件指针   ->  fseek()  -> man 3 fseek

#include <stdio.h>

int fseek(FILE * stream, long  offset, int whence);

stream: 需要进行偏移的文件指针

offset: 需要偏移的偏移量

whence: 基准点

SEEK_SET  -> 文件开头

SEEK_CUR  -> 文件当前位置

SEEK_END  -> 文件末尾

返回值:

成功:0

失败:-1

2.  获取当前文件指针距离开头的绝对值

#include <stdio.h>

long ftell(FILE *stream);

stream:需要获取当前位置距离开头的字节数的文件指针

返回值:

成功: 距离开头的偏移量

失败: -1

3. 重置文件指针的定位到开头

#include <stdio.h>

void rewind(FILE *stream);

stream: 文件指针

返回值:无!

等价: fseek(stream, 0, SEEK_SET)

练习3: 使用文件IO中标准IO接口实现文件的拷贝

例如: ./xxx 1.txt 2.txt

要求1: 1.txt必须存在,并且不知道里面有多少个字节数

要求2: 2.txt不存在则创建,存在则清空

要求3: 无论1.txt中有多少个字节,拷贝完后,2.txt必须与1.txt一致。

#include <stdio.h>

int main(int argc,char *argv[])  //  ./copy 1.txt 2.txt

{

char buf[10] = {0};

int n;

long a,b;

FILE *fp1 = fopen(argv[1],"r");

if(fp1 == NULL)

printf("fp1 error!\n");

FILE *fp2 = fopen(argv[2],"w");

if(fp2 == NULL)

printf("fp2 error!\n");

while(1)

{

a = ftell(fp1);

n = fread(buf,5,2,fp1);

//还没有到达文件末尾

if(n == 2)

{

fwrite(buf,10,1,fp2);

}

//到达文件末尾

if(n < 2)

{

b = ftell(fp1);

fwrite(buf,b-a,1,fp2);

break;

}

}

fclose(fp2);

fclose(fp1);

return 0;

}

六. printf()函数缓冲区问题。

printf()默认的输出对象是标准输出,是有缓冲区。这个缓冲区需要某些特定的条件才会输出数据。

printf()是一个行缓冲区函数,当遇到‘\n‘就会将之前的数据全部输出。

例子1:

int main(int argc,char *argv[])

{

printf("helloworld");

printf("yueqian");

return 0;

}

结果: 会输出helloworldyueqian

结论: 程序退出时,会刷新printf()函数的缓冲区。

例子2:

int main(int argc,char *argv[])

{

printf("helloworld");

printf("yueqian");

while(1);

return 0;

}

结果: 不输出任何内容

结论: 程序没有结束的时候,缓冲区是不会输出!

例子3:

int main(int argc,char *argv[])

{

printf("helloworld");

printf("yueqian\n");

while(1);

return 0;

}

结果: 会输出helloworldyueqian

结论: 当遇到\n时,就会将缓冲区中所有内容都会输出。

例子4:

sleep(1);  -> 进程挂起1秒

usleep(500000);   -> 进程挂起0.5秒

int main()

{

while(1)

{

printf("helloworld");

usleep(100000);

}

return 0;

}

结果: 等到缓冲区满了,就会将缓冲区的数据全部输出。

结论: printf()缓冲区满了,即使程序不退出,也没有\n,也是会所有的内容都输出来。

例子5:

主动刷新数据缓冲区  ->  fflush()  -> man 3 fflush

NAME

fflush - flush a stream  -> 刷新文件流指针

#include <stdio.h>

int fflush(FILE *stream);

stream:需要刷新的文件指针。

返回值:

成功:0

失败:-1

int main(int argc,char *argv[])

{

printf("helloworld");

fflush(stdout);

while(1);

return 0;

}

结果: 会输出helloworld

结论: 当执行fflush(stdout);刷新标准输出的缓冲区时,缓冲区中的内容就会全部输出。

例子6:

int main()

{

printf("pls input a num:");

scanf("%d",&a);

}

结果: 会输出pls input a num:

结论: 当调用IO函数,就会刷新缓冲区

例子7:

printf()  -> 对象  -> 标准输出   ->  有缓冲区

-> 标准出错   ->  无缓冲区

fprintf()  -> 修改输出对象

#include <stdio.h>

int fprintf(FILE *stream, const char *format, ...);

stream: 修改后的对象的文件指针

format: 输出的格式

printf("hello");  等价于  fprintf(stdout,"hello");

int main()

{

while(1)

{

fprintf(stderr,"helloworld");

usleep(100000);

}

return 0;

}

结果: 每隔0.1S输出一个helloworld。

结论: 标准出错没有缓冲区。

总结printf()能输出的情况。

1. 程序退出

2. 遇到\n

3. 缓冲区满了

4. 主动使用fflush刷新缓冲区

5. 使用fprintf()修改输出对象

6. 再次调用IO函数刷新缓冲区

七. 关于标准IO特殊函数

getchar()  getc()   fgetc()  putc()  fputc()  puts()  fputs()  fgets()

1. getchar()  -> 阻塞从IO缓冲区中获取一个字符

#include <stdio.h>

int getchar(void);

参数:无

返回值:

成功:获取到的字符

失败:-1

例子:

#include <stdio.h>

int main()

{

int ret;

ret = getchar();

printf("%c\n",ret);

return 0;

}

注意:

getchar()  等价于  getc(stdin);

2. getc()   fgetc() -> 阻塞从文件指针中获取一个字符。

#include <stdio.h>

int getc(FILE *stream);

stream: 文件指针

返回值:

成功: 获取到的字符

失败: -1

练习4: 使用getc将某个文件的内容一个一个字符地输出来!

#include <stdio.h>

int main()

{

/*

int ret;

ret = getchar();

printf("%c\n",ret);

*/

FILE * fp = fopen("test.txt","r");

while(1)

{

int ret = getc(fp);

if(ret == -1)

{

break;

}

printf("%c\n",ret);

}

fclose(fp);

return 0;

}

3. putc()  fputc()  -> 输出一个字符到屏幕上

#include <stdio.h>

int putc(int c, FILE *stream);

c: 输出的字符

stream: 文件指针

返回值:

成功: 写入的字符

失败: -1

4. puts()    -> 输出字符串到屏幕上  -> man 3 puts

fputs()   -> 输出字符串到文件指针上  -> man 3 fputs

int fputs(const char *s, FILE *stream);

int puts(const char *s);

s: 字符串的首地址

stream: 文件指针

返回值:

成功: 没有使用过的整型数据

失败: -1

puts(s) 等价于  printf("%s\n",s);

5. fgets()  -> 从键盘中获取字符串  -> 包含\n在内

#include <stdio.h>

char *fgets(char *s, int size, FILE *stream);

s: 缓冲区的地址

size: 字节数大小

stream:文件指针

返回值:

成功:指向s这个区域的地址

失败:NULL

#include <stdio.h>

int main()

{

char buf[50] = {0};

fgets(buf,50,stdin);

printf("buf = %s",buf);

if(strncmp(buf,"hello",5) == 0)   如果使用strcmp(),就不匹配!

{

printf("ok!\n");

}else{

printf("error!\n");

}

return 0;

}

原文地址:https://www.cnblogs.com/zjlbk/p/11252167.html

时间: 2024-08-29 16:36:30

2019年7月26日星期五(文件IO)的相关文章

2019年2月26日【整理物品,下载收集考研资料,明天正式开始复习】

2019年1月26日星期六 一:一句话木马重学习 1.网站安全狗网马查杀 http://download.safedog.cn/download/software/safedogwzApache.exe 2.D盾 Web 查杀 http://www.d99net.net/down/WebShellKill_V2.0.9.zip 3 深信服WebShellKillerTool http://edr.sangfor.com.cn/tool/WebShellKillerTool.zip 4 BugSc

【2019年4月26日】最新指数基金估值表(坚持定投终能胜利)

(本篇文章阅读时间约2分钟) 大家好,我是牛九老师,专注于研究指数基金领域很多年,欢迎来到[牛九老师的投资者大家庭]. 每天我会给大家分享投资心得,发布最新的指数基金估值. 每天只需五分钟,大家跟随老师一起坚持投资自己.实现财富增值,战胜通货膨胀,共同走向财务自由之路,过上自己真正想要的生活! 我们坚持在每周四(下午三点之前)进行指数基金的定投,届时会向大家推荐当期的定投组合,强烈推荐大家在支付宝中购买基金,方便安全有保障! 下面是我为大家精心制作的2019年4月26日[第106期]指数基金估值

2019年6月26日:日历问题、整数求和、奇数求和

题目描述: 假设 2012 年 1 月 1 日是星期日,请求出 n 天后是星期几 输入描述: 多组输入每组输入一个正整数 n (1 <= n <= 2000) 输出描述: 对于每组输入,输出 1 个整数 i (1 <= i <= 7),表示 n 天后是星期几 样例输入: 1 2 样例输出: 1 2 #include<iostream> using namespace std; int main(){ int n; while(cin>>n) cout<

实验报告(2019年6月26日)

c程序实验报告 姓名:黄志乾????实验地点:教学楼514教室????实验时间:4月30日 一.本章要点 1.通过实验理解结构体和共用体的数据结构 2.结构体.共用体中数组的使用及变量的赋值 3.结构体和共用体定义时的嵌套使用(嵌套使用的结构体必须先定义) 二.实验内容 1.实验练习:9.1 问题描述:试利用结构体类型描述年.月.日,输入一个日期,统计该日期是本年度第多少天. 流程图 实验代码 #include<stdio.h> main() { struct date { int year,

2019年5月26日-linux就该这么学-第11课

第9章 使用 ssh服务管理远程主机 9.1 配置网络服务9.1.1 配置网络参数--nmtui(1) 网卡配置文件中 ONBOOT yes,这样在系统重启后网卡就被激活了.(2) 手动重启服务:systemctl restart network:9.1.2 创建网络会话--网络会话功能允许用户在多个配置文件中快速切换.nmcli--基于命令行的网络配置工具,用于管理NetworkManager服务.(1) 查看网络连接情况:nmcli connection show:(2) 配置company

2019年7月26日(数学、DP)

难受,爆零!! 哎--讲题吧 prob1:A 题目大意:两种操作:把某数二进制上某一位翻转或异或一个集合中的一个数,求从\(s\)变到\(t\)的最少步数 \(sb\)题,完完全全的水题,结果\(bfs\)的队列写萎了 第一种操作可以转成第二种,而每个数最多只被异或一次,一通\(bfs\)瞎搞就可以了.但最小步数更新需在入队时,并将是否更新作为入队条件,否则会\(T,RE\)炸掉(别问我怎么知道的) 贴代码: #include<iostream> #include<cstring>

2019年5月26日

距离考核结束的时间只剩下5天了,一个特别大的问题就是前后端的交流问题,不单单是项目的进度,更多的是人与人之间的交流.页面的进度完成了一整个流程,剩下的就是和后端的进行交互,后端的进度有点慢,导致我现在还没有真正意义上的完成过一次交互,但今天有前端的小伙伴说我写的页面的JavaScript有些没有实现完,我也是今天才发现这个问题,所以页面的进度不能说是完成了,我们也需要进行页面的改动,整个项目大体上说算是都没有完成.最最重要的也许就是组员们之间的交流问题了吧,没有进行及时的前后端交流,没有耐下心来

2019年8月26日至29日面试记录

话不多说,这是一次伤心的面试经历,有了面试机会,奈何自己不争气,面了几家,终于认清,还是自己太菜了,技术方面还是没有达到一定的水准,至少没有达到面试官感觉能用的水准.努力学习还是目前生活中的唯一主旋律.        总结这次面试遇到的问题(我面的是Java开发岗位)        1.基础肯定是要弄懂得,哪怕你真的不是能全记住,你面试前也要过一遍,加深一下记忆,面试中肯定会遇到.        2.后台框架,目前主流的框架你要知道,比如现在流行的spring boot ,spring clou

2019年10月26日 复习

描述符:描述对象的一种方法  __get__  __set__ __delete__  至少使用了其中一种. 描述符何时何地使用: 何地:定义成另一个类的类属性 何时:被描述的类在操作属性的时候会触发 描述符:1 没有set方法  叫做 非数据描述符 2 有get和set 叫做 数据描述符 优先级: 1类属性>2数据描述符>3实例属性>4非数据描述符>5找不到的属性触发getattr type 是python中内置的元类 原文地址:https://www.cnblogs.com/p