2019年7月24日星期三(文件io)

. 文件IO学习大纲

1. 文件IO概念,文件概念,文件类型..

2. 如何在linux下系统IO访问一个文件?关闭文件?读取文件?写入文件?

3. 文件描述符概念?研究文件描述符数值。文件描述符与文件关系?

4. 文件偏移量

5. 使用文件IO -> 系统IO 进行实际应用  -> LCD液晶

6. 内存映射访问文件。

7. 文件  -> 标准IO接口,如何访问?如何关闭?如何读取?如何写入?

8. 标准IO一些特殊API函数

9. 目录IO,目录检索,访问目录,切换目录,读取目录,关闭目录..

. linux文件概念

1. 什么是文件?

linux下,一共有7种文件类型,连目录/硬件都属于文件。   -> 在linux下,一切都是文件。

2. 什么是文件IO

就是对这7种文件进行数据的输出(output)/输入(input)

文件输入:  -> 将数据写入到文件

文件输出:  -> 将文件的内容读取出来

3. 如何实现文件的读取/写入?   -> 直接使用linux系统的函数接口

 手册数

  2   System calls (functions provided by the kernel)  -> 系统调用函数  -> 系统IO接口都是在2手册

  3   Library calls (functions within program libraries)  -> 库调用函数  -> 标准IO接口都是在3手册

4. 使用系统IO来访问文件与标准IO有什么区别?

系统IO  -> 无缓冲区  -> 有多少数据就处理多少数据

标准IO  -> 有缓冲区  -> 一块一块数据地写/

  对象: 硬件设备  -> LCD液晶、触摸屏、LED灯  -> 系统IO

  对象: 普通文件  -> a.c b.txt c.jpg d.mp3  -> 标准IO

. 使用系统IO来访问文件?

1. 如何访问文件?   ->  open()   -> man 2 open

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <fcntl.h>

    int open(const char *pathname, int flags);

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

       flags: 操作文件的权限

              O_RDONLY  -> 只读

              O_WRONLY  -> 只写

              O_RDWR    -> 可读可写

    返回值:

       成功: 新的文件描述符 >=0   最小非负没有使用过的整数

       失败: -1

2. 如何关闭文件?  -> close()  -> man 2 close

    #include <unistd.h>

    int close(int fd);

     fd:需要关闭的文件描述符   -> 该数值一定是已经打开过的文件描述符。

   返回值:

       成功:0

       失败:-1

 练习1: 在ubuntu中建立一个新的文件叫test.txt,写一个程序访问该文件,并查看文件描述符的值,并关闭它!

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

int main()

{

       int fd,ret;

       fd = open("test.txt",O_RDONLY);

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

       ret = close(fd);

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

       return 0;

}

 练习2: 尝试访问板子中/dev/fb0这个文件,并关闭!

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

int main()

{

       int fd,ret;

       fd = open("/dev/fb0",O_RDONLY);

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

      

       ret = close(fd);

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

      

       return 0;

}

.文件描述符?

1. 什么是文件描述符呢?

文件描述符是open()函数的返回值,如果open()执行成功,那么就会返回一个非负最小并且没有使用过的整型数据。

例子: 

3 = open("./test.txt");

4 = open("/1.c");

A105 = open("关国源");

其中3和4就是文件描述符,也就是说3这个数字就代表了test.txt这个文件。4代表1.c这个文件,A105代表关国源,将来只需要操作这些数字,就等价于操作对应的文件。

2. 访问文件时,发现fd等于3,说明012已经被占用,究竟是被谁占用了?

其实系统在启动时,就会默认打开3个文件,分别是"标准输入"、"标准输出"、"标准出错",它们都是一个宏定义来的,是被定义在一个头文件,头文件的路径:/usr/include/unistd.h

/* Standard file descriptors.  */

#define  STDIN_FILENO      0     -> 标准输入   -> 对象就是键盘   ->  理解: 0 = open("键盘")

#define  STDOUT_FILENO  1     -> 标准输出   -> 对象就是屏幕   ->  理解: 1 = open("液晶屏幕")        -> 有缓冲区

#define  STDERR_FILENO   2     -> 标准出错   -> 对象就是屏幕   ->  理解: 2 = open("液晶屏幕错误信息") -> 无缓冲区

练习3: 验证文件描述符特性:  非负最小并且没有使用过的整型数据

       当前目录下a.txt b.txt c.txt d.txt

        open(a.txt);

       open(b.txt);

       open(c.txt);         

       关闭b.txt;

       open("d.txt");

       关闭a.txt;

       open(b.txt);//3

       关闭c.txt;

       open(a.txt);//5

       open(c.txt);//6

       关闭d.txt;

       ? = open(d.txt); //4

  分配原则:最小并且是没有使用过的int非负整型数。

3. 研究文件描述符的最大值?

例子:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

int main()

{

       int fd;

       while(1)

       {

              fd = open("./test.txt",O_RDONLY);

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

              if(fd == -1)

                     break;

       }

       return 0;

}

结论:文件描述符范围:0~1023

. open()函数拓展参数

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <fcntl.h>

     int open(const char *pathname, int flags);

     int open(const char *pathname, int flags, mode_t mode);

       flags: 操作文件的权限/文件的属性

必选三选一:

O_RDONLY  -> 只读

O_WRONLY  -> 只写

O_RDWR    -> 可读可写

可选的额外参数(可选可不选)

In  addition,  zero  or  more  file creation flags and file status flags can be bitwise-or'd in flags.

       如果使用0或者多个标志位,那么就使用"|"连接在一起。

O_CREAT   -> 如果文件不存在,则创建该文件。   -> 需要填mode这个参数,这个参数代表新文件的权限。

            If  the  file  does not exist it will be created.

mode  specifies  the permissions to use in case a new file is created.  This argument must be supplied when O_CREAT is specified in flags; if O_CREAT is not specified, then mode is ignored.

O_EXCL  -> 存在则报错

          pathname already exists, then open() will fail.

O_APPEND   -> 以追加的方式写入文件内容。  -> write()

O_TRUNC  ->  文件存在则清空。  -> 必须三选一中只能选O_WRONLY/O_RDWR

O_TRUNCO_CREAT一般会连用。

练习4: 自己写代码验证O_CREAT、O_TRUNC、O_EXCL这参数。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

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

{

       int fd;

       fd = open("./test.txt",O_RDWR|O_CREAT|O_TRUNC,0777);

       return 0;

}

.文件的数据IO处理  -> 读取/写入数据

1. 读取文件的数据   -> read()  -> man 2 read

功能: read - read from a file descriptor  -> 从文件描述符中读取数据,而不是从文件中读取

   #include <unistd.h>

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

   fd:文件描述符

   buf: 数据缓冲区的地址

   count: 尝试从文件中读取的字节数   -> 这仅仅是一个愿望值。

  返回值:

       成功:实际读取到字节数

       失败:-1

  例题: 尝试从文件中读取一些字节出来? test.txt

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <strings.h>

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

{

       int fd;

       char buf[100] = {0};

       //1. 打开文件

       fd = open("./test.txt",O_RDWR); //"yueqian"

       //2. 读取文件

       int n;

       n = read(fd,buf,5);

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

       printf("buf = %s\n",buf); //yueqi

       bzero(buf,sizeof(buf));

       n = read(fd,buf,5);

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

       printf("buf = %s\n",buf); //an

       //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

练习5: test.txt  -> 清空,将"helloworld"写入到文件中。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <string.h>

int main()

{

       int fd = open("test.txt",O_RDWR|O_TRUNC);

       char *p = "helloworld";

       write(fd,p,strlen(p));

       close(fd);

       return 0;

}

练习6: 验证write()文件偏移问题。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <string.h>

int main()

{

       char buf[100] = {0};

       int fd = open("test.txt",O_RDWR);

       read(fd,buf,2);

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

       write(fd,"abc",3);

       bzero(buf,sizeof(buf));

       read(fd,buf,2);

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

       close(fd);

       return 0;

}

练习7: 验证open()函数的O_APPEND参数。

O_APPEND  -> 如果打开文件时使用了O_APPEND,那么打开文件之后,文件的定位在文件的末尾!

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <string.h>

int main()

{

       int fd = open("test.txt",O_RDWR|O_APPEND);

       write(fd,"apple",strlen("apple"));

       close(fd);

       return 0;

}

. 文件偏移量

文件偏移量就是当前文件定位,默认打开文件时,文件定位都是在最开头。

1IO函数可以使得偏移量进行偏移。

例子:  fd = open("test.txt");  -> 偏移量为0

       write(fd,"hello",5);    -> 偏移量为5

2)如何使得不调用IO函数前提下偏移定位?   -> 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  -> 相对于文件的末尾

这个几个宏是被定义在/usr/include/unistd.h

# define SEEK_SET 0     /* Seek from beginning of file.  */

# define SEEK_CUR      1     /* Seek from current position.  */

# define SEEK_END      2     /* Seek from end of file.  */

       返回值:

              成功: 返回值距离文件开头的字节数

              失败: -1

记住:

1. 新打开文件定位一定是最开头。

2. 读取文件可以导致偏移量的移动。

3. 使用lseek()可以导致偏移量的移动。

4. 相对于文件当前位置与相对于文件末尾是不一样的。

  练习8: 验证lseek第三个参数。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <string.h>

int main()

{

       char buf[50] = {0};

       int fd = open("test.txt",O_RDWR);

       read(fd,buf,2);

       printf("buf = %s\n",buf);//he

       int ret = lseek(fd,5,SEEK_CUR);

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

       //read(fd,buf,sizeof(buf));

       //printf("buf = %s\n",buf);

       ret = lseek(fd,-4,SEEK_END);

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

       bzero(buf,sizeof(buf));

       read(fd,buf,sizeof(buf));

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

       return 0;

}

猜你喜欢

转载自www.cnblogs.com/zjlbk/p/11239894.html
今日推荐