文件数据输出输入

tech2022-09-12  124

一、文件数据输出/输入。 1、如何读取文件的数据?  -> read()  -> man 2 read 函数功能:read from a file descriptor     //读取一个文件描述符的数据 头文件:     #include <unistd.h>

原型:     ssize_t read(int fd, void *buf, size_t count);

参数:     fd:文件描述符     buf:数据缓冲区     count:尝试读取的字节数(愿望值)

返回值:     成功:已经成功读取到的字节数     失败:-1

  例子1: 尝试从文本中读取一些数据出来。

注意:从文本文档中读取出来的数据,都是字符串。

int main(int argc,char *argv[]) {     //1. 打开目标文件     int fd;     fd = open("./test.txt",O_RDONLY);     if(fd < 0)     {         printf("open file error!\n");     }          //2. 读取数据     char buf[100] = {0};     int n;     n = read(fd,buf,5);     printf("n = %d\n",n);     printf("from file:%s\n",buf);          //3. 关闭文件     close(fd);          return 0; } 结果: n = 10 from file:helloworld

   练习1: 重复读取一个文件,那么第二次读取的时候是在第一次基础上继续读,还是重新读?  -> 继续读

int main(int argc,char *argv[]) {     //1. 打开目标文件     int fd;     fd = open("./test.txt",O_RDONLY);     if(fd < 0)     {         printf("open file error!\n");     }          //2. 读取数据     char buf[100] = {0};     int n;     n = read(fd,buf,5);     printf("n = %d\n",n);     printf("from file:%s\n",buf); //hello          n = read(fd,buf,5);     printf("n = %d\n",n);     printf("from file:%s\n",buf); //world          //3. 关闭文件     close(fd);          return 0; }

2、写入数据到文件中。 -> write()  -> man 2 write 函数功能: write to a file descriptor     //写入数据到文件描述符中 头文件:     #include <unistd.h>

原型:     ssize_t write(int fd, const void *buf, size_t count); 参数:     fd:文件描述符     buf:需要写入到文件中的内容     count:写入的字节数

返回值:     成功:真正写入字节数     失败:-1

  例子2:尝试写一些数据到空白的文件中。

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h>

int main(int argc,char *argv[]) {     int fd;     fd = open("./test2.txt",O_WRONLY|O_TRUNC);     if(fd < 0)     {         printf("open file error!\n");     }          char buf[20] = "helloworld";     int n;     //n = write(fd,buf,strlen(buf)); //内容是:helloworld     //printf("n = %d\n",n); //10          //n = write(fd,buf,5); //内容是:hello     //printf("n = %d\n",n); //5          //n = write(fd,buf,20); //内容是:helloworld + 10个空格     //printf("n = %d\n",n); //20          n = write(fd,buf,100); //内容是:helloworld + 10个空格 + 乱码      printf("n = %d\n",n); //n=100          close(fd);          return 0; }       练习2: 重复写入一个文件,那么第二次写入的时候是在第一次基础上继续写,还是重新写?   -> 继续写

n = write(fd,buf,5); //内容是:hello printf("n = %d\n",n); //5      n = write(fd,buf,5); //内容是:hello printf("n = %d\n",n); //5

文件内容:hellohello

   练习3: 先读取一些数据,然后再写,那么写的时候是重新写,还是读取完的那个位置继续写?  -> 继续写

             //文本内容:yueqianhelloworld

read(fd,buf,5); //yueqi printf("buf = %s\n",buf); //yueqi      char *p = "apple"; write(fd,p,strlen(p));   //内容:yueqiappleloworld

   练习4: 验证O_APPEND在写操作时,会追加?  -> 会追加。

      打开一个文件,写入数据          -> 从头开始写的。       打开一个文件|O_APPEND,写入数据  -> 从文件末尾开始写。

fd = open("./test2.txt",O_RDWR|O_APPEND); // yueqiappleloworld      char *p = "kkk"; write(fd,p,strlen(p));

文本内容:yueqiappleloworldkkk

      O_APPEND会影响读操作吗?  -> 不会

    打开一个文件,读取数据            -> 从头开始读     打开一个文件|O_APPEND,读取数据   -> 从头开始读        二、文件偏移量。 1、什么是文件偏移量? 文件偏移量就是文件当前的定位,默认打开一个文件时,文件的定位都是在最开头。

2、怎么样才能使得文件偏移量发生偏移? 1)使用读写操作的函数可以使得文件偏移量发生偏移。    fd=open("test.txt");   //偏移量:0    write(fd,"hello",5);   //偏移量:5

2)如何使得不调用读写函数前提下发生偏移?  ->  lseek()  -> man 2 lseek 函数功能:reposition read/write file offset     //重新定位读写的偏移量

头文件:     #include <sys/types.h>         #include <unistd.h>

原型:     off_t lseek(int fd, off_t offset, int whence);

参数:     fd:需要发生偏移的文件的文件描述符     offset:需要偏移的字节数 [+] (往后偏移)  [-] (往前偏移)       whence:         SEEK_SET: 相对于文件的开头。                SEEK_CUR: 相对于当前的位置进行偏移。                SEEK_END: 相对于文件的末尾发生偏移。

返回值:     成功:距离文件开头字节数。     失败:-1

  例子:验证lseek的参数。

int main(int argc,char *argv[]) {     int fd;     fd = open("./test.txt",O_RDWR); //偏移量:0    helloworld          int ret;     ret = lseek(fd,3,SEEK_SET);  //偏移量:3     printf("ret = %d\n",ret);//3          char buf[10] = {0};     read(fd,buf,5);      printf("from file:%s\n",buf);//lowor          ret = lseek(fd,-3,SEEK_CUR);     printf("ret = %d\n",ret);//5     read(fd,buf,5);      printf("from file:%s\n",buf);//world           close(fd);          return 0; }                如果当前偏移量已经在开头,还往前偏移会怎么样? lseek()函数就会返回失败,返回-1,当前的文件定位还在0。

如果当前偏移量已经在文件的末尾,还往后偏移会怎么样? 会发生偏移,但是如果偏移完之后没有写入东西,那么在windows中看到还是在文件末尾。 如果发生偏移之后,写入东西了,那么就会在windows中看到空格。

三、linux系统IO应用实例。  -> LCD液晶屏幕。 1、在linux下,一切都是文件。 连lcd液晶屏幕也是一个文件,既然是一个文件,那么lcd液晶对应的文件名是什么? lcd液晶  -> 硬件设备  -> 去开发板下"/dev"目录下寻找。

/dev/fb0           -> lcd液晶设备 /dev/input/event0  -> 触摸屏设备 /dev/ttySAC0       -> 拓展串口1 /dev/ttySAC1       -> 拓展串口2 /dev/ttySAC2       -> 拓展串口3 /dev/ttySAC3       -> 拓展串口4

2、已知lcd液晶设备名字,就可以使用open函数去访问设备,如果我们要写一些数据(颜色)进去,那么首先必须要了解lcd液晶参数。 1)屏幕尺寸:7寸 2)分辨率:800*480   -> 像素点总数 3)每一个像素点都是由三原色组成的,所以像素点可以显示任何一种颜色。 三原色:红绿蓝。    那么每一个像素点占用多少个字节?

[root@GEC6818 /]#cat /sys/class/graphics/fb0/bits_per_pixel  32   -> 每一个像素点 = 32位      -> 每一个像素点 = 4个字节,分别是ARGB

  例子: 尝试写颜色到lcd屏幕上,看看有没有效果?

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>

int main(int argc,char *argv[]) {     /* 1. 访问lcd液晶屏幕 */     int lcd;     lcd = open("/dev/fb0",O_WRONLY);     if(lcd < 0)     {         printf("open lcd error!\n");     }          /* 2. 准备颜色,然后写入到lcd设备上 */     int color = 0x00FF0000; //红色     write(lcd,&color,4);          /* 3. 关闭文件 */     close(lcd);          return 0; }

结果: 整个屏幕的第一个像素点显示为红色。

   练习1: 显示满屏的紫色。

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>

int main(int argc,char *argv[]) {     /* 1. 访问lcd液晶屏幕 */     int lcd;     lcd = open("/dev/fb0",O_WRONLY);     if(lcd < 0)     {         printf("open lcd error!\n");     }          /* 2. 准备颜色,然后写入到lcd设备上 */     int color = 0x00FF00FF; //紫色     int i;     for(i=0;i<800*480;i++)     {         write(lcd,&color,4);     }          /* 3. 关闭文件 */     close(lcd);          return 0; }

   练习2: 验证0x00FFFF00是黄色。  -> 是的    练习3: 黑色和白色是多少?        黑色:0x00000000        白色:0x00FFFFFF

四、内存映射。 1、内存映射方式与普通文件IO方式有什么区别? 例如:想把一些数据写入到文件中。 普通文件IO: open()访问文件  -> 得到一个文件描述符fd  -> 直接往文件描述符fd写入数据就可以了   -> 关闭文件描述符fd。

内存映射: open()访问文件  -> 得到一个文件描述符fd  -> 根据文件描述符fd去内存空间上映射一块空间,得到一个地址p  -> 用户只需要将数据拷贝到内存空间上就可以了   -> 对应的文件就会有相应的变化   -> 撤销映射   -> 关闭文件描述符fd。

2、内存映射主要作用对象:lcd设备。 详细步骤: 1)通过访问文件的方式,得到文件描述符。    int lcd = open("/dev/fb0",O_RDWR);

2)根据文件描述符lcd去内存空间上映射一块空间。  -> mmap()  -> man 2 mmap 函数功能:map files or devices into memory     //将文件/设备映射到内存空间上

头文件:#include <sys/mman.h> 原型:     void *mmap(void *addr, size_t length, int prot, int flags,                   int fd, off_t offset);

参数:     addr:不为NULL  -> 用户选择内存空间上的地址。 0.0000001%           NULL      -> 系统为用户选择空间。  99.99999%     length:映射的内存长度  例如:lcd液晶  800*480*4     prot:         PROT_EXEC  Pages may be executed.                PROT_READ  Pages may be read.                PROT_WRITE Pages may be written.         PROT_NONE  Pages may not be accessed.         如果需要使用多个权限,则使用"|"连接在一起,例如: PROT_READ|PROT_WRITE     flags:         MAP_SHARED  -> 共享的         MAP_PRIVATE -> 私有的     fd:文件描述符     offset:文件偏移量,(从文件的那个字节开始偏移)

返回值:     成功:指向那片内存空间的区域的地址     失败:-1

3)拷贝数据到空间上。  -> memcpy()  -> man 3 memcpy 函数的功能: copy memory area     //拷贝数据到内存空间上

头文件:     #include <string.h>

原型:     void *memcpy(void *dest, const void *src, size_t n);

参数:     dest:目标内存空间的地址。      src:需要拷贝的数据(颜色)     n:需要拷贝的总字节数。

返回值:     成功:指向dest这个区域的地址     失败:NULL

4)那么对应的文件就会有对应的效果。 5)撤销映射。  ->  munmap()  -> man 2 munmap 功能: unmap files or devices into memory     //撤销映射

头文件:     #include <sys/mman.h>

原型:     int munmap(void *addr, size_t length);

参数:     addr:需要撤销内存空间的地址。     length:需要撤销的长度。

返回值:     成功:0     失败:-1

6)关闭文件。    close(lcd);

    例题2:使用内存映射的方式来显示全屏紫色。      #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <string.h>

int main(int argc,char *argv[]) {     int lcd,i;     int *p = NULL;          /* 1. 访问lcd液晶设备 */     lcd = open("/dev/fb0",O_RDWR);     if(lcd < 0)         printf("open lcd error!\n");          /* 2. 根据文件描述符fd去内存上映射一块区域 */     p = (int*)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);     if(p == (void *)-1)         printf("mmap error!\n");          /* 3. 准备颜色 */     int red_color = 0x00FF00FF;          /* 4. 将颜色数据拷贝到映射的空间上 */     for(i=0;i<800*480;i++)     {         memcpy(p+i,&red_color,4);     }          /* 5. 撤销映射 */     munmap(p,800*480*4);          /* 6. 关闭文件 */     close(lcd);          return 0; }

   练习4: 将int*,修改为char*,程序应该怎么改?

for(i=0;i<800*480;i++) {     memcpy(p+i,&red_color,4); } 修改成: for(i=0;i<800*480*4;i+=4) {     memcpy(p+i,&red_color,4); }

   练习5: 使用内存映射完成以下的效果。

最新回复(0)