linux应用编程 (高级编程)
IO
多任务
网络
IO(文件)
文件操作:
文本文件,mp3,jpeg,png ,mp4,avi
文件:
一组相关数据的有序集合
文件名:
这组相关数据的一个名称
linux里面对文件的处理:
思想:
一切皆文件 ,文件用来存储数据(数据、指令)
everything is file!
b c d - l p s
b -- block -- 块设备文件 --- 硬盘(存储设备)
c -- character -- 字符设备文件 --- 鼠标 (输入输出设备)
d -- directory -- 目录文件
- -- regular -- 普通文件 (分类:二进制文件:.jpg .bmp .mp4 a.out
ASCLL文件: .txt .c .h)
l -- link -- 软连接文件 --- 类似windows的快捷方式
p -- pipe -- 管道文件 --- 实现操作系统中 进程间的一些 信息交换(通信)
s -- socket -- 套接字文件 --- 网络的时候 (进程间的通信)
【操作文件的基本思路及框架】//凡是文件,都可从这个思路出发进行思考
文件操作三步骤:
1.打开
2.读写
3.关闭
Linux提供的两种文件操作方式:
文件编程:
1.标准IO --- 库函数 -------标准c库函数,
2.文件IO --- 系统调用-------Linux内核为用户提供的函数接口
系统调用:Linux内核为用户提供的函数接口
库函数:标准c库函数, 对Linux内核中系统调用的封装
标准IO库:
1.标准io的概念
1975 Dennis Ritchie编写, IO库,
从C语言的标准,ANSI c
IO input output
I: 键盘是标准输入设备 ====》默认输入就是指键盘 /dev/input
O: 显示器是标准输出设备 ==》默认输出就是指显示器
Linux操作系统当中IO都是对文件的操作
C一部分,任何支持标准C的系统都可使用标准IO实现文件存储
标准IO在UNIX上是对文件IO的封装
一般都是对普通文件操作是一种有缓存的IO 在文件IO和用户程序之间,
加入缓冲区,可以有效减少系统调用的次数,节省系统IO调度资源
2.功能:
用来操作普通文件
普通文件:
1.ASCII码文件(代码、文本文件)
2.二进制文件(音视频、图片)
ASCII码文件是一种特殊的二进制文件
2021
'2' '0' 2' '1'
2021
0000 0000 0000 0000 0000 0111 1110 0101
3.操作方法
1.打开 -- fopen //FILE open
2.读写 --
fgetc / fputc 读出、写入单个字符
fgets / fputs 读出、写入一行字符
fread / fwrite 读出、写入指定长度数据
3.关闭 -- fclose
man手册
标准man手册分为8个章节:
man 1 用户命令
man 2 系统调用
man 3 c函数库调用
man 4 设备文件和特殊文件
man 5 配置文件和格式
man 6 游戏相关
man 7 杂项,总述
man 8 管理类命令
4.API函数接口
1.fopen
#include
FILE* fopen(const char *path, const char *mode);
功能:
流打开函数 (打开文件,并关联到一个流)
参数:
@pathname --要打开的文件的文件名(字符串形式)
@mode --打开文件的操作模式
r ---打开文件做读操作
注意:
文件必须存在
文件必须存在
r+ 打开文件做写操作
w 打开文件做读写操作
注意:
注意:
如果文件已经存在,则会将文件清空为0
如果文件不存在,则会创建一个新文件。
w+ 打开文件做读写操作
如果文件已经存在,则在文件末尾进行写入
如果文件不存在,则会创建一个新文件。
a+ 打开文件做读写操作
注意:
如果文件已经存在,则会将文件清空为0
如果文件不存在,则会创建一个新文件。
a 打开文件做写操作
注意:
注意:
如果文件已经存在,则在文件末尾进行写入
如果文件不存在,则会创建一个新文件。
返回值:
成功 FILE * (文件流指针)
失败 NULL 并且 设置 errno 表明错误原因
od -c 查看ASCLL中的字符
cat 将文件中字符打印到终端
流:
数据从文件当中流入和流出所体现出来的字节流叫做流
FILE 结构定义的对象(FILE * 指向的对象)称之为流对象,FILE *叫文件流指针。
标准IO将对文件的操作转换成了对"流"的操作。
所以,标准IO的文件相关的函数都是围绕着 FILE进行的。
FILE * fp
FILE * fp;//流指针------关联一个文件
FILE * 实际上是指向了一块内存空间(缓存,fileno)
FILE *fp <->【FILE结构体[缓存,fileno]】//堆区(malloc)
2.fclose
int fclose(FILE *fp);
功能:
关闭文件流指针
参数:
fp:文件流指针
返回值:
成功返回0
失败返回EOF(-1)
注意:fopen操作完毕后使用fclose关闭,否则会产生内存泄漏
不要重复调用fclose
练习:
用fopen实现一个touch的功能!
(如何从命令行获取 文件名,然后进行操作)
- #include <stdio.h>
-
- int main(void)
- {
- FILE *fp = NULL;
-
- fp = fopen("1.txt","r+");
-
- if (fp == NULL)
- {
- printf("没有这个文件!!!\n");
- return 0;
- }
-
- printf("存在这个文件!!!\n");
-
- char s[32] = "hello world!";
- int i = 0;
-
- while (s[i] != '\0')
- {
- fputc(s[i],fp);
- fputc(s[i],stdout);
- i++;
- }
-
- fputc('\n',stdout);
-
- fclose(fp);
-
- return 0;
- }
3.fputc
int fputc(int c, FILE *stream);
功能:
向流中写入一个字符
参数:
c:要写入的字符
stream:文件流指针
返回值:
成功返回 写入的字符ASCII码值
失败返回 EOF
练习:利用fputc实现在file.txt文件中写入hello world
- #include <stdio.h>
-
- int main(void)
- {
- FILE *fp = NULL;
-
- fp = fopen("1.txt","r+");
-
- if (fp == NULL)
- {
- printf("没有这个文件!!!\n");
- return 0;
- }
-
- printf("存在这个文件!!!\n");
-
- char s[32] = "hello world!";
- int i = 0;
-
- while (s[i] != '\0')
- {
- fputc(s[i],fp);
- fputc(s[i],stdout);
- i++;
- }
-
- fputc('\n',stdout);
-
- fclose(fp);
-
- return 0;
- }
//读
4.fgetc
int fgetc(FILE *stream);
功能:
从流中读取一个字符
参数:
stream:文件流指针
返回值:
成功返回读到字符的ASCII码值
读到文件末尾 返回 EOF
失败返回EOF EOF
操作系统在运行一个程序时,会默认打开三个流:
stdin FILE* 标准输入流 ---->键盘
stdout FILE* 标准输出流 ---->屏幕
stderr FILE* 标准出错流 ---->屏幕
gets scanf getchar -> stdin
puts printf putchar -> stdout
perror -> stderr
练习:
1.从终端输入数据并输出(fgetc、fputc)
- #include <stdio.h>
-
- int main(int argc, const char *argv[])
- {
- if (argc < 2)
- {
- printf("恁弄啥嘞,加文件名( ⊙ o ⊙ )啊!\n");
- return 0;
- }
- FILE *fp = fopen(argv[1],"r");
-
- if (fp == NULL)
- {
- printf("没有这个文件!!!\n");
-
- return -1;
- }
-
- printf("存在这个文件!!!\n");
-
- int ret = 0;
-
- while (ret != -1)
- {
- ret = fgetc(fp);
-
- if (ret == -1)
- {
- break;
- }
-
- fputc(ret,stdout);
- }
-
- fclose(fp);
-
- return 0;
- }
2.用fgetc 从键盘获取数据 --- fgetc(stdin);
将获取到的数据 写入到一个文件中。---fputc(ch,fp);
如果输入q 表示输入结束!
stdin --获取数据 --- fgetc
fp --保存数据 --- fputc(ch,fp); // fp --- fopen
等价:
ch = getchar();
ch = fgetc(stdin);
等价:
putchar(ch);
fputc(ch, stdout);
- #include <stdio.h>
-
-
- int main(int argc, const char *argv[])
- {
- while (1)
- {
- fputc(fgetc(stdin), stderr);
- }
-
- //int ret = fgetc(stdin); ====> int ret = getchar();
- //fputc(ret, stdout); ====>putchar(ret);
-
-
- return 0;
- }
练习2:
cp src.txt dest.txt
- #include <stdio.h>
-
-
- int main(int argc, const char *argv[])
- {
- if (argc < 3)
- {
- printf("Usage: ./a.out
\n" ); - return 0;
- }
-
- FILE *srcfp = fopen(argv[1], "r");
- FILE *dstfp = fopen(argv[2], "w");
- if (NULL == srcfp || NULL == dstfp)
- {
- printf("fail fopen\n");
- return -1;
- }
-
- while (1)
- {
- int ret = fgetc(srcfp);
- if (EOF == ret)
- {
- break;
- }
- fputc(ret, dstfp);
-
- }
-
- fclose(srcfp);
- fclose(dstfp);
-
- return 0;
- }
//面试题:
fgetc()/fputc()面试题:
如何用最短的代码实现用户任意输入并打印输出。
要求用fgetc/fputc函数实现。
while(1)
fputc(fgetc(stdin),stdout);
while(fputc(fgetc(stdin),stdout))
;
//注意点:
fgetc()函数的结束判断。
1、EOF 宏来判断 ===》系统预制的文件结束标记
end of file -1
5.fputs
int fputs(const char *s, FILE *stream);
功能:
向流中写入一行字符串
参数: s
要写的信息,一般是固定的字符串或者有数据的数组。
stream
要写入的目标文件流对象
返回值:成功 nonnegative number on success
失败 -1;
注:
不写入 '\0'
- #include
-
-
- int main(int argc, const char *argv[])
- {
- FILE *fp = fopen("1.txt", "w");
- if (NULL == fp)
- {
- printf("fail fopen\n");
- return -1;
- }
- char str[] = {"hello world"};
- char *p = "hello world";
- int ret = fputs("hello world", fp);
- if (ret < 0)
- {
- printf("fail fputs\n");
- }
- fputs(str, fp);
- fputs(p, fp);
-
-
- fclose(fp);
-
- return 0;
- }
puts和fputs的区别:
1.fputs不会自动增减\n
2.puts 会多打印\n字符
6.fgets
//按行读写 按字符串读写
fgets -- char ---> string
fputs -- char ---> string
char *fgets(char *s, int size, FILE *stream);
功能:
从stream流对象关联的文件中获取size大小字节的文本数据
并存储到s对应的本地内存(栈区数组,堆区内存)
参数: s 要存储数据的本地内存(栈,堆)
size 要获取的数据长度,单位字节。
stream 要获取的目标文件流对象,
可以是stdin ,程序会阻塞等待
如果是普通文件fp 则指向文件第一行数据
返回值:成功 返回指向有效数据的首地址,一般等于s的地址
失败 或者 文件末尾 NULL;
- #include <stdio.h>
-
- int main(int argc, const char *argv[])
- {
- FILE *fp = fopen("1.txt", "r");
- if (NULL == fp)
- {
- printf("fail fopen\n");
- return -1;
- }
-
- char str[32] = {0};
-
- while (1)
- {
- char *p = fgets(str, 32, fp);
- if (NULL == p)
- {
- break;
- }
- printf("str = %s\n", str);
- }
-
- fclose(fp);
-
- return 0;
- }
注意:
1.fgets能读取一行就读取一行
2.fgets会读到n个数据,如果n个数据中存在\n字符则立即停止当
前的读取操作,如果没有\n,则读取n-1个字符,最后一个存储\0
3.fgets每行读取的数据后面都有一个\n,在\n后面存放一个\0
12345
buf[] = '1''2''3''4''5''\n''0'
4.gets是危险的,因为没有规范读到数据的上限
5.gets会去掉从终端读入的\n字符 //也读走了\n 但是将 \n 去掉了 \n --> '\0'
作业
1. 使用fgets\fputs实现文件的拷贝 ./a.out src dst 要求:测试两种普通文件类型
- #include <stdio.h>
-
- int main(int argc, const char *argv[])
- {
- if (argc < 3)
- {
- printf("error\n");
- return 0;
- }
- FILE *fp1 = fopen(argv[1],"r");
- FILE *fp2 = fopen(argv[2],"w");
-
- if (NULL == fp1 || NULL == fp2)
- {
- printf("error\n");
-
- return -1;
- }
-
- char s[10000];
-
- while (1)
- {
- char *p = fgets(s,1024,fp1);
- if (NULL == p)
- {
- break;
- }
- int ret = fputs(p,fp2);
- if (ret < 0)
- {
- printf("fail fputs\n");
- }
-
- }
-
- fclose(fp1);
- fclose(fp2);
- return 0;
- }
2. 统计一个文本文件中,各种字符出现的次数
- #include <stdio.h>
-
- int main(int argc, const char *argv[])
- {
- if (argc < 2)
- {
- printf("error\n");
- return 0;
- }
-
- int cnt[128] = {0};
- int ret = 0;
-
- FILE *fp = fopen(argv[1],"r");
- while (1)
- {
- ret = fgetc(fp);
-
- cnt[ret]++;
-
- if (EOF == ret)
- {
- break;
- }
-
- }
-
- for (ret = 0; ret < 128; ret++)
- {
- printf("cnt[%d] = %-3d ",ret,cnt[ret]);
-
- if (ret % 10 == 0)
- {
- printf("\n");
- }
- }
-
- printf("\n");
-
- return 0;
- }