常见的操作系统:
1.Windows:界面友好,使用方便。闭源收费。pc
2.Linux:类Unix,开源免费。嵌入式平台
2.Unix:收费
4.FreeRTOS:小型嵌入式平台,实时性
一、文件编程(IO)
IO:input/output 输入/输出
1.为什么学习文件操作
1.保存数据,掉电数据不丢失,保存在硬盘(外存)
2.一切皆文件(硬盘、鼠标、键盘、显示器、普通文件....)
2. Linux下的文件类型
ls -l 查看Linux下的文件相关详情(ll)
cpp
d rwx rwx r-x 2 linux linux 4096 11月 5 2024 serial
文件类型 文件读写可执行权限 硬链接个数 用户自己 组长 文件大小 文件最后被修改的时间
rwx:自己对文件的读写可执行权限
rwx:同组用户对文件的读写可执行权限
rwx:其他人
cpp
b c d - l s p七种文件类型 *
b ---block ---块设备文件(硬盘)
c ---character ---字符设备文件(鼠标、键盘、显示器、外设传感器...)
d ---directory ---目录文件(文件夹)
- ---regular ---普通文件(xxx.c xxx.h a.out xxx.jpg...)
l ---link ---链接文件(类似于快捷方式)
s ---socket ---套接字文件(网络通信)
p ---pipe ---管道文件(进程间通信)
3. 文件操作方法
Linux下的两种文件操作方式:
标准IO:C标准库提供的对文件的操作接口(库函数)如printf、scanf
文件IO:Linux内核提供的对文件的操作方法(系统调用)
文件操作思想:
1.打开文件
2.读写文件
3.关闭文件
4. 标准IO
学习标准C库提供的一堆对文件的操作接口(函数)-----》通过man手册
1.打开文件:fopen
2.读写文件:fgetc/fputc、fgets/fputs、fread/fwrite
3.关闭文件:fclose
cpp
man手册
标准man手册分为8个章节:
man 1 用户命令
man 2 系统调用
man 3 c函数库调用
man 4 设备文件和特殊文件
man 5 配置文件和格式
man 6 游戏相关
man 7 杂项,总述
man 8 管理类命令
函数接口:
1. fopen
cpp
FILE *fopen(const char *pathname, const char *mode);
功能:打开一个文件,并获得一个文件流指针
参数:
pathname:文件名
mode:文件的打开方式
"r" 以只读方式打开,文件必须存在
"r+" 以读写方式打开,文件必须存在
"W" 以只写方式打开,文件存在则清空,文件不存在则创建
"w+" 以读写方式打开,文件存在则清空,文件不存在则创建
"a" 以追加写的方式打开,文件不存在则创建
"a+" 以读和追加写的方式打开,文件不存在则创建
返回值:
成功:返回文件流指针FILE *
失败:NULL
文件流:从文件中读写数据时体现出来的字节流。文件流指针:FILE*。
标志IO中对文件的操作都是面向文件流指针。
2. fclose
cpp
int fclose(FILE *stream);
功能:关闭文件
参数:
stream:已打开的文件的文件流指针
返回值:
成功:0
失败:EOF(-1)
3. fputc
cpp
int fputc(int c, FILE *stream);
功能:向文件中写入一个字符
参数:
c : 要写入的字符的ASCII值
stream:要写入的文件流指针
返回值:
成功:写入的字符的ASCII值
失败:EOF(-1)
练习:1. 使用fputc向文件中写入"hello world"
od -c 文本文件名 :以字符方式查看该文件中的数据
cpp
int main()
{
FILE*fp = fopen("1.txt","w+");
if(fp == NULL)
{
printf("fopen malloc\n");
}
char a[12] = "hello world";
int len = strlen(a);
for(int i = 0;i<len;i++)
{
fputc(a[i],fp);
}
fclose(fp);
return 0;
}
4. fgetc
cpp
int fgetc(FILE *stream);
功能:从文件中读取一个字符
参数:
stream:文件流指针
返回值:
成功:读到的字符的ASCII值
失败:EOF(-1)
读到文件末尾:EOF
练习:
使用fgetc实现cat的功能,将一个指定的文本文件内容输出到终端。
cpp
#include<stdio.h>
int main(int argc,char*argv[])
{
if(argc < 2)
{
printf("usage:./a.out <filename>\n");
return -1;
}
FILE*fp = fopen(argv[1],"r");
if(fp == NULL)
{
printf("fopen error");
return -1;
}
int ret = 0;
while(1)
{
ret = fgetc(fp);
if(ret == EOF)
{
break;
}
printf("%c",ret);
}
fclose(fp);
return 0;
}
使用fgetc和fputc实现文件的拷贝,使用主函数传参的方式实现。
cpp
int copy_file(const char*srcname,const char*dstname)
{
FILE*fpsrc = fopen(srcname,"r");
FILE*fpdst = fopen(dstname,"w");
if(fpsrc == NULL || fpdst == NULL)
{
printf("fopen error\n");
return -1;
}
char str = 0;
while(1)
{
str = fgetc(fpsrc);
if(str == EOF)
{
break;
}
fputc(str,fpdst);
}
fclose(fpsrc);
fclose(fpdst);
}
int main(int argc,char*argv[])
{
if(argc < 2)
{
printf("usage <srcname> <dstname>\n");
return -1;
}
copy_file(argv[1],argv[2]);
return 0;
}
三个操作系统已经打开的文件流:stdin stdout stderr
cpp
三个操作系统已经打开的文件流:
FILE *
stdin --->标准输入流---》关联的文件:输入设备:键盘
stdout --->标准输出流---》关联的文件:输出设备:显示屏
stderr --->标准出错流---》关联的文件:显示屏
fgetc和getchar:ret = getchar() ====>ret = fgetc(stdin);
fputc和putchar:putchar(ret) =====>fputc(ret, stdout);
5. fgets
cpp
char *fgets(char *s, int size, FILE *stream);
功能:从文件中读取一行
参数:
s:存放读取数据的内存首地址
size:希望从文件中读到的字节数
stream:要读的文件的文件流指针
返回值:
成功:返回s的地址
失败:NULL
读到文件末尾:NULL
实现cat的功能
gets和fgets的区别
gets只能从终端读取数据;fgets可以任意文件流指针中读取
fgets会保留用户收入的\n字符,gets不会读取\n字符
fgets安全的,gets是危险的:fgets最多读取size-1个数据,最后一个位置存放字符串结束标志;
gets没有大学的限制
6. fputs
cpp
int fputs(const char *s, FILE *stream);
功能:向文件中写入一行数据
参数:
s :要写入的数据的首地址
stream:要写入的文件
返回值:
成功:>0
失败:EOF(-1)
注意:不会将字符串结束标志'\0'字符写入文件
fgets和fputs不能处理二进制文件,
练习:
利用fgets和fputs实现文件拷贝
cpp
#include<stdio.h>
int file_copy(const char*srcname,const char*dstname)
{
FILE*fpsrc = fopen(srcname,"r");
FILE*fpdst = fopen(dstname,"w");
if(NULL == fpsrc || NULL == fpdst)
{
printf("fopen error\n");
return -1;
}
while(1)
{
char buff[128] = {0};
char*p = fgets(buff,sizeof(buff),fpsrc);
if(NULL == p)
{
break;
}
fputs(buff,fpdst);
}
fclose(fpsrc);
fclose(fpdst);
return 0;
}
int main(int argc,char*argv[])
{
if(argc < 3)
{
printf("usage ./a.out srcname dstname\n");
return -1;
}
file_copy(argv[1],argv[2]);
return 0;
}
统计文件中各种字符个数
cpp
#include<stdio.h>
int main(int argc,char*argv[])
{
if(argc < 2)
{
printf("usage:./a.out filename\n");
return -1;
}
int cnt[256] = {0};
FILE*fp = fopen(argv[1],"r");
if(NULL == fp)
{
printf("fopen error\n");
return -1;
}
int ret = 0;
while(1)
{
ret = fgetc(fp);
if(EOF == ret)
{
break;
}
cnt[ret]++;
}
int sum = 0;
for(int i = 0;i<256;i++)
{
if(cnt[i]!= 0)
{
printf("%c : %d is %d\n",i,i,cnt[i]);
}
}
fclose(fp);
return 0;
}
结果:

其他
1.主函数传参
程序运行时,命令行传递的参数可通过主函数传参的方式,传递给程序。
实参:命令行参数
形参:int main(int argc, const char *argv\[\])
argc:命令行传递的参数个数 argv:指针数组:多个指针,分别指向命令行传递的参数
cpp
./a.out aaa bbb
argv[0] : ./a.out
argv[1] : aaa
argv[2] : bbb
2.const修饰的指针
cpp
const char *p; ---->const修饰p指向的内容,表示该内容只读(不能被修改)
char const *p; ---->同上
char *const p; ---->const修饰指针p,表示指针的指向不能发生修改
const char *const p; ---->p指针指向不能被修改,指向的内容也不能被修改
3. 普通文件(-)
ASCII文件(文本文件): '2' '0' '2' '6' xxx.c xxx.h xxx.txt
二进制文件:0/1 011111101010 a.out xxx.png xxx.jpg xxx.bmp xxx.mp4