嵌入式 -文件IO

一、标准IO

在这里插入图片描述
解释:用户应用程序可以直接调用系统驱动,实现操作。但是存在着多种多样的系统,因此需要一个统一的标准来来适配所有的系统,因此通过c库函数来调用系统内核驱动。
全缓冲
当流的缓冲区无数据或无空间时才执行实际I/O操作
行缓冲
当在输入和输出中遇到换行符(‘\n’)时,进行I/O操作
当流和一个终端关联时,典型的行缓冲
无缓冲
数据直接写入文件,流不进行缓冲

标准预定义I/O
在这里插入图片描述

文件的打开和关闭

标准I/O – fopen – mode参数
在这里插入图片描述
标准I/O – 处理错误信息
extern int errno;
void perror(const char *s);
char *strerror(int errno);
errno 存放错误号,由系统生成
perror先输出字符串s,再输出错误号对应的错误信息
strerror根据错误号返回对应的错误信息
标准I/O – 关闭文件
int fclose(FILE *stream);
fclose()调用成功返回0,失败返回EOF,并设置errno
流关闭时自动刷新缓冲中的数据并释放缓冲区
当一个程序正常终止时,所有打开的流都会被关闭。
流一旦关闭后就不能执行任何操作

文件读写

字符的输入(读单个字符):
int fgetc(FILE *stream);
int getc(FILE *stream); //宏
int getchar(void);
成功时返回读取的字符;若到文件末尾或出错时返回EOF(-1),
getchar()等同于fgetc(stdin)
getc和fgetc区别是一个是宏一个是函数

注意事项:
1函数返回值是int类型不是char类型,主要是为了扩展返回值的范围。
2 stdin 也是FILE *的指针,是系统定义好的,指向的是标准输入(键盘输入)
3 打开文件后读取,是从文件开头开始读。读完一个后读写指针会后移。读写注意文件位置!
4 调用getchar会阻塞,等待你的键盘输入

字符的输出(写单个字符):
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

成功时返回写入的字符;出错时返回EOF
putchar©等同于fputc(c, stdout)
注意事项:
1返回和输入参数都是int类型
2遇到这种错误:Bad file descriptor, 很可能是文件打开的模式错误(只读模式去写,只写模式去读)

行输入(读取整个行)
char *gets(char *s); 读取标准输入到缓冲区s
char *fgets(char *s, int size, FILE *stream);

成功时返回s,到文件末尾或出错时返回NULL
遇到’\n’或已输入size-1个字符时返回,总是包含’\0’

注意事项:
1 gets函数已经被淘汰,因为会导致缓冲区溢出
2 fgets 函数第二个参数,输入的数据超出size,size-1个字符会保存到缓冲区,最后添加’\0’,如果输入数据少于size-1 后面会添加换行符。

行输出(写整行)

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

成功时返回非负整数;出错时返回EOF
puts将缓冲区s中的字符串输出到stdout,并追加’\n’
fputs将缓冲区s中的字符串输出到stream,不追加 ‘\n’

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 
  5 int main(){
  6     FILE* fp;
  7     char data[100]={"abcdef"};
  8     int ret;
  9     char* r;
 10     fp=fopen("1.txt","r+");
 11     if(fp==NULL){
 12         perror("fopen");
 13         return -1;
 14     }
 15     
 16    ret=fputs(data,fp);
 17    if(ret==-1){
 18     perror("fputs");
 19    }
 20    
 21    // r=fgets(data,5,stdin);
 22     r=fgets(data,10,fp);
 23     
 24     if(r==NULL){
 25         perror("fgets");
 26     }
 27     printf("fgets:%s\n",data);
 28     
 29     if((ret=fclose(fp))==-1){
 30         
 31         perror("fclose");
 32     }
 33     
 34     return 0;
 35 

二进制文件读写

文本文件和二进制的区别:
存储的格式不同:文本文件只能存储文本。

计算机内码概念:文本符号在计算机内部的编码(计算机内部只能存储数字0101001…,所以所有符号都要编码)

二进制读写函数格式:
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
void *ptr 读取内容放的位置指针
size_t size 读取的块大小
size_t n 读取的个数
FILE *fp 读取的文件指针

size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
void *ptr 写文件的内容的位置指针
size_t size 写的块大小
size_t n 写的个数
FILE *fp 要写的文件指针

注意事项:
文件写完后,文件指针指向文件末尾,如果这时候读,读不出来内容。
解决办法:移动指针(后面讲解)到文件头;关闭文件,重新打开

1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 typedef struct {
  5     char name[20];
  6     int age;
  7     char sex[8];
  8 
  9 }student;
 10 
 11 int main(){
 12     student stu;
 13     student stu_r;
 14     strcpy(stu.name,"zhangsan");
 15     stu.age=61;
 16     strcpy(stu.sex,"male");
 17     
 18     FILE* fp;
 19     if((fp=fopen("1.bin","w+"))==NULL){
 20         perror("fopen:");
 21         return 0;
 22     }
 23     size_t ret;
 24     
 25     ret=fwrite(&stu,sizeof(stu),1,fp);
 26     if(ret==-1){
 27         perror("fread");
 28         return 0;
 29     }
 30     fclose(fp);
 31     
 32     if((fp=fopen("1.bin","r"))==NULL){
 33         perror("fopen");
 34         return 0;
 35     }
 36     
 37     ret=fread(&stu_r,sizeof(stu),1,fp);
 38     if(ret==-1){
 39         perror("fread");
 40     }
 41     printf("name=%s age=%d sex=%s\n",stu_r.name,stu_r.age,stu_r.sex);
 42    if((ret=fclose(fp))==-1){
 43         perror("fclose");
 44         return 0;
 45    }
 46 
 47     return 0;
 48 
 49 
 50 
 51 }
                                

文件流的刷新和定位

流的刷新
int fflush(FILE *fp);

成功时返回0;出错时返回EOF
将流缓冲区中的数据写入实际的文件
Linux下只能刷新输出缓冲区,输入缓冲区丢弃

如果输出到屏幕使用fflush(stdout)

流的定位:
long ftell(FILE *stream);
long fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
fseek 参数whence参数:SEEK_SET/SEEK_CUR/SEEK_END
SEEK_SET 从距文件开头 offset 位移量为新的读写位置
SEEK_CUR:以目前的读写位置往后增加 offset 个位移量
SEEK_END:将读写位置指向文件尾后再增加 offset 个位移量
offset参数:偏移量,可正可负

注意事项:
1.文件的打开使用a模式 fseek无效
2.rewind(fp) 相当于 fseek(fp,0,SEEK_SET);
3.这三个函数只适用2G以下的文件

编译告警错误:
ffseek_t.c:13:11: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
printf(“current fp=%d\n”,ftell(fp));
表示参数类型不匹配

 1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 
  5 int main(){
  6     FILE* fp;
  7     int ret;
  8     fp=fopen("1.txt","r+");
  9     if(fp==NULL){
 10         perror("fopen");
 11     }
 12 
 13     char data[10]={"abcdef"};
 14 
 15     ret=fputs(data,fp);
 16     printf("fputs location=%ld\n",ftell(fp));
 17     if(ret==-1){
 18         perror("fputs");
 19     }
 20     //fseek(fp,-2,SEEK_CUR);
 21 
 22     fseek(fp,2,SEEK_SET);
 23     
 24     printf("fseek location=%ld\n",ftell(fp));
 25     ret=fputs("123",fp);
 26     
 27     
 28     fclose(fp);
 29 
 30     return 0;
 31 
 32 
 33 
 34 }

格式化输出
int fprintf(FILE *stream, const char *fmt, …);
int sprintf(char *s, const char *fmt, …);

成功时返回输出的字符个数;出错时返回EOF

格式化输入
int fscanf(FILE *stream, const char *format, …);
int sscanf(const char *str, const char *format, …);

重点掌握sprintf 和sscanf
格式化输入输出练习
sysytime_t.c

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 #include<time.h>
  5 #include<unistd.h>
  6 /*
  7 
  8 struct tm {
  9                int tm_sec;    
 10                int tm_min;    
 11                int tm_hour;   
 12                int tm_mday;   
 13                int tm_mon;    
 14                int tm_year;   
 15                int tm_wday;   
 16                int tm_yday;   
 17                int tm_isdst;  
 18            };
 19 
 20 */
 21 
 22 
 23 int main(){
 24     FILE* fp;
 25     time_t ctime_t;
 26     struct tm* ctime;
 27     int linecount=1;
 28     char data[32]={0};
 29     fp=fopen("time_t.txt","a+");
 30     if(fp==NULL){
 31         perror("fopen");
 32         return -1;
 33     }
 34     while(fgets(data,32,fp)!=NULL){
 35         if(data[strlen(data)-1]=='\n'){
 36             linecount++;
 37         }
 38     
 39     }
40 
 41 
 42 
 43 
 44     while(1){
 45         ctime_t=time(NULL);
 46         //printf("%ld",ctime_t);
 47         ctime=localtime(&ctime_t);
 48         printf("%d-%d-%d %d:%d:%d\n",ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,
 49                                     ctime->tm_hour,ctime->tm_min,ctime->tm_sec);
 50         fprintf(fp,"%d %4d-%2d-%2d %2d:%2d:%2d\n",linecount++,ctime->tm_year+1900,ctime->tm_mon+1,ctime->tm_mday,
 51                                                 ctime->tm_hour,ctime->tm_min,ctime->tm_sec);
 52         fflush(fp);
 53         sleep(1);
 54 
 55     }
 56     fclose(fp);
 57     return 0;
 58 
 59 
 60 
 61 
 62 
 63 
 64 }

二、文件IO

文件IO的概念

什么是文件IO,又称系统IO,系统调用
是操作系统提供的API接口函数。
POSIX接口 (了解)
注意:文件IO不提供缓冲机制

文件IO的API

open close read write

文件描述符概念:

英文:缩写fd(file descriptor)
是0-1023的数字,表示文件。
0, 1, 2 的含义 标准输入,标准输出,错误

文件IO 打开

open
int open(const char *pathname, int flags); 不创建文件
int open(const char *pathname, int flags, mode_t mode); 创建文件,不能创建设备文件
成功时返回文件描述符;出错时返回EOF
在这里插入图片描述

文件IO和标准的模式对应关系:

r O_RDONLY
r+ O_RDWR
w O_WRONLY | O_CREAT | O_TRUNC, 0664
w+ O_RDWR | O_CREAT | O_TRUNC, 0664
a O_WRONLY | O_CREAT | O_APPEND, 0664
a+ O_RDWR | O_CREAT | O_APPEND, 0664

umask概念:
umask 用来设定文件或目录的初始权限

文件的关闭
int close(int fd)
关闭后文件描述符不能代表文件

文件IO的读写和定位

容易出错点:
求字符串长度使用sizeof,对二进制数据使用strlen
printf 的字符最后没有’\0’

文件io测试代码

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<unistd.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7     
  8 int main(){
  9     int fd;
 10     int ret;
 11    fd=open("file_io.txt",O_RDWR | O_CREAT | O_APPEND,0664);
 12    if(fd<0){
 13         printf("open file failed\n");
 14         return 0;
 15    }
 16     char data[32]={"hello wrold"};
 17     char data2[32]={0};
 18     ret=write(fd,data,strlen(data));
 19     if(ret==-1){
 20         printf("write failed\n");
 21         goto END;
 22     }
 23     printf("write %d\n",ret);
 24     
 25     lseek(fd,0,SEEK_SET);
 26     
 27     ret=read(fd,data2,32);
 28     if(ret==-1){
 29         printf("read failed\n");
 30         goto END;
 31     
 32     }
 33     data2[31]=0;
 34     printf("ret=%d ,%s\n",ret,data2);
 35 END:
 36     close(fd);
 37     return 0;
 38 
 39 }

三、目录

打开目录

#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd); 使用文件描述符,要配合open函数使用
DIR是用来描述一个打开的目录文件的结构体类型
成功时返回目录流指针;出错时返回NULL

读取目录

#include <dirent.h>
struct dirent *readdir(DIR *dirp);

struct dirent是用来描述目录流中一个目录项的结构体类型
包含成员char d_name[256] 参考帮助文档
成功时返回目录流dirp中下一个目录项;
出错或到末尾时时返回NULL

关闭目录

closedir函数用来关闭一个目录文件:
#include <dirent.h>
int closedir(DIR *dirp);

成功时返回0;出错时返回EOF

修改文件权限

chmod/fchmod函数用来修改文件的访问权限:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);

成功时返回0;出错时返回EOF
注意:在vmware和windows共享的文件夹下,有些权限不能改变。

获取文件属性

#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);

成功时返回0;出错时返回EOF
如果path是符号链接stat获取的是目标文件的属性;而lstat获取的是链接文件的属性

四、库的概念:

静态库

创建静态库步骤:
1 . 编写库文件代码,编译为.o 目标文件。
2.ar 命令 创建 libxxxx.a 文件
ar -rsv libxxxx.a xxxx.o
注意:1 静态库名字要以lib开头,后缀名为.a
2 没有main函数的.c 文件不能生成可执行文件。

链接错误:
test.c:(.text+0x15):对‘hello’未定义的引用
collect2: error: ld returned 1 exit status
含义:表示hello函数在编译的源码内没有找到实现
解决:实现代码或者找到对应函数的库并且链接它。

链接静态库:

gcc -o 目标文件 源码.c -L路径 -lxxxx

-L 表示库所在的路径
-l 后面跟库的名称

动态库的生成步骤:

1.生成位置无关代码的目标文件
gcc -c -fPIC xxx.c xxxx.c … -c
2.生成动态库
gcc -shared -ols
libxxxx.so xxx.o xxx.o …

3.编译可执行文件
gcc -o 目标文件 源码.c -L路径 -lxxxx
执行动态库的可执行文件错误
./test: error while loading shared libraries: libmyheby.so: cannot open shared object file: No such file or directory

含义:可执行文件所使用的动态库找不到
解决办法:
找到动态库,添加到/usr/lib里面
或者使用export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你的动态库目录
添加在~/.bashrc 文件里面
使用source ~/.bashrc 生效。

查看可执行文件使用的动态库:
ldd 命令 : ldd 你的可执行文件
root@haas-virtual-machine:/mnt/hgfs/share/newIOP# ldd test
linux-vdso.so.1 => (0x00007fff6548d000)
libmyheby.so => /mnt/hgfs/share/newIOP/day5/libmyheby.so (0x00007f5c89521000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c89144000)
/lib64/ld-linux-x86-64.so.2 (0x000055fe52211000)

root@haas-virtual-machine:/mnt/hgfs/share/newIOP/day5# ldd test
linux-vdso.so.1 => (0x00007ffcb652c000)
libmyheby.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbeeffaf000)
/lib64/ld-linux-x86-64.so.2 (0x0000561003c3b000)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值