linux中(文件io)的系统io、标准io、目录io

  • 文件IO简介
  1. 什么是文件IO?

==> Linux 下一切都是文件!

Linux环境下,Linux把所有的资源统一当成文件来进行对待,那么在Linux环境下要使用各种设备,那就需要对对应的设备问价进行访问。但是在操作系统的管理下,用户是不允许直接对文件进行操作。Linux系统给开发者预留了一些对文件操作的函数接口,这些函数接口就是文件IO。

文件IO其实就是对文件操作的一些函数接口(API)

  1. 文件IO分类
  1. 系统IO

==> 功能由系统内核直接提供。(功能更为原始,更为接近底层),使用时通常在对底层设备文件进行访问的时候使用系统IO。

==> open , read, write, close, lseek, mmap ....

  1. 标准IO

==> 功能由标准库提供。(底层调用类系统IO)

==> 带缓冲的IO,处理速度比系统IO要快!

==> 在应用层对于文件文件的处理时通常采用标准IO

        ==> fopen , fread, fwrite, fclose, fseek,  fputs, fgets ...

  • 相关函数
  1. open()   --> 打开或者创建文件  --> man 2 open

open, creat - open and possibly create a file or device

SYNOPSIS

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <fcntl.h> //头文件(在程序中使用open函数需要声明头文件)

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

==> pathname : 路径名  (需要打开的文件的路径名)

==> flags : 标志 (打开文件之后的权限!)

O_RDONLY, //只读权限

        O_WRONLY, //只写权限

O_RDWR. //读写权限

==> 返回值: 成功返回一个新的文件描述符,失败返回-1.

//文件描述符:对文件操作的一把钥匙(本质是一个大于等于0的整数)(数组的下标)

//硬盘:一栋大楼

//文件:大楼里面的房间

//操作系统:大楼管理员

// open函数 :找大楼管理员拿钥匙

// close函数 :把钥匙还给管理员

==> 例子: 使用open函数,打开当前路径下的一个文件1.txt. 如果成功,打印一下文件描述符的值。

 

==> 为什么文件描述符的值是3?

==> 程序在运行时,会默认打开3个文件描述符

0 标准输入 STDIN_FILENO 键盘

1 标准输出 STDOUT_FILENO 屏幕

2 标准出错 STDERR_FILENO 屏幕

==> 这些定义是在 /usr/include/unistd.h

==> 一个程序中,文件打开的数量是不是无限的?   (一个程序中同一时刻打开的文件数量是有限制的!)

==> 测试:对一个文件进行循环打开,直到打开出错就停止!

==> Linux下程序同时打开文件的数量上限 1024

==> 如果想要无限的打开文件,那么对于不再需要使用的文件要及时的关闭(close)

 

==> 注意:在文件操作的时候,对于一些不再需要使用的文件来说,需要及时的关闭它,否则可能造成程序打不开新的文件!

==> open函数在打开文件的时候,可以添加参数,实现文件不存在的情况下可以创建文件并且打开!

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

==> 如果要创建文件,需要在第二个参数中添加 O_CREAT,那么就需要对第三个参数进行赋值,给它新建的文件的权限

==> 例子: 打开当前路径下的文件2.txt, 如果文件不存在则创建他,并且把文件权限设置为对所有用户都是可读可写不可执行。

2,read()  从文件中读取数据 --> man 2 read

NAME

       read - read from a file descriptor

SYNOPSIS

       #include <unistd.h>

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

==> fd : 需要读取数据的文件描述符

==> buf : 存放数据的缓冲区( void * :任意类型指针 )

==> count : 想要一次读取的字节数!  

返回值:成功返回实际读取的字节数,0代表读取到文件末尾,失败返回-1

 

 

==》例子:从文件open.c 中读取数据并且打印.

--> 1) 打开文件 open.c

--> 2) 读取文件数据

--> 3) 关闭文件 open.c

练习1:先把read.c 自己去动手敲一遍,熟悉一下read函数的用法。

==> 然后修改代码,实现把open.c文件的所有内容全部输出!

==> 思考:要把一个文件中的所有数据都读取出来,应该怎么读取?

解决方案:

·把read函数的缓冲区设置的大一点!

·读文件内容进行循环读取!直到读取到文件末尾时结束!

==> 示例代码:

 

 

1,write函数

NAME

       write - write to a file descriptor

SYNOPSIS

       #include <unistd.h>

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

==> fd : 需要写入的文件的文件描述符  

==> buf : 想要写入到文件内容的缓冲区首地址(可以写入任意类型数据)

==> count : 想要写入的字节数!

返回值: 成功返回实际写入的字节数(0代表没有写入东西),失败返回 -1

 

 

Write函数使用案例:

write写入字符串

Write写入整型,浮点型...

Write写入结构体

  1. lseek函数   --> 偏移文件指针

NAME

       lseek - reposition read/write file offset

SYNOPSIS

       #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(fd,  3,  SEEK_SET);

偏移到文件末尾:lseek(fd,  0,  SEEK_END);

偏移到文件倒数第2个字节: lseek(fd, -2, SEEK_END);

 

 ==> 例子: 使用lseek函数偏移文件指针,跳过文件1.txt 的前个字符,把后面的内容全部读取。

 

  • 什么是标准IO?

标准IO是由POSIX库提供的一套文件IO,这套文件IO对系统IO进行封装调用,使功能更加丰富,调用更为简单,方便应用层的程序进行调用。简单来说,标准IO就是调用系统IO实现文件IO操作的一套函数接口!

1,系统IO与标准IO之间的关系

底层:系统IO  --> open

应用层:标准IO  --> fopen

  • 标准IO的相关函数
  1. fopen()

==> man 3 fopen

NAME

       fopen, fdopen, freopen - stream open functions

SYNOPSIS

       #include <stdio.h>

       FILE *fopen(const char *path, const char *mode);

==> path : 打开的文件的路径

==> mode : 打开的方式

--> “r” : 以只读权限打开文件,文件指针指向文件开头!

-->”r+” : 以读写权限打开文件,文件指针指向文件开头!

-->”w” : 如果文件不存在,那就创建文件。如果文件存在,那就先清空文件,然后以只写的权限打开文件,文件指针指向文件开头

-->”w+” : 如果文件不存在,那就创建文件。如果文件存在,那就先清空文件,然后以读写的权限打开文件,文件指针指向文件开头

-->”a” : 以追加的形式打开文件,如果文件不存在则创建,打开之后文件指针指向文件末尾。

-->”a+” : 读写打开文件,如果文件不存在则创建,文件的读指针指向文件开头(读取数据会从文件开头开始读),文件的写指针指向文件末尾(往文件里面写数据是追加写入)。

返回值: 成功返回FILE * 指针,失败返回NULL

 

  1. fclose() -->

SYNOPSIS

       #include <stdio.h>

       int fclose(FILE *stream);

==> 例子:打开一个文件”1.txt”,如果文件不存在则创建,存在则清空!

练习1:使用fopen函数实现功能:以追加形式打开一个文件 2.txt,如果文件不存在则创建,打开成功输出:”open file success!” .

==>程序运行时,默认打开3个文件流

0 stdin :标准输入 --> 键盘

1 stdout :标准输出 --> 屏幕

2   stderr :标准出错 --> 屏幕

==> 文件流定义在 stdio.h  --> /usr/include/stdio.h

  1. fread()/fwrite()   ==> 读写文件

NAME

       fread, fwrite - binary stream input/output

SYNOPSIS

       #include <stdio.h>

       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

       size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

==> ptr : 存放 读取/写入 数据的缓冲区的首地址

==> size : 读取/写入 数据的每一块的大小!单位字节

==> nmemb : 读取/写入 的数据块的块数

==> stream : 文件流指针

返回值:成功返回实际读取的数据块数量,读取完毕或者失败返回0.可以通过函数feof(3) and ferror(3)判断是失败还是读取到文件末尾。

 

 ==> 例子2: 以只写方式打开文件1.txt, 写入”helloworld” 字符串到文件中.

==》例子3:以只读方式打开文件1.txt,将里面的内容读取出来。

 

  1. fseek() --> 偏移文件指针

NAME

       fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream

SYNOPSIS

       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);

       long ftell(FILE *stream); //返回文件指针相对于文件开头的偏移量

==> stream : 文件流指针

==> offset : 偏移的字节数

==> whence : 偏移的位置

SEEK_SET : 文件开头

SEEK_CUR : 当前指针位置

SEEK_END : 文件末尾

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

 

 

==> 例子1:使用标准IO相关函数,实现读取文件 fwrite.c 的最后10个字符!。

·打开文件 fopen

·偏移文件指针到倒数第10个字符

·读10个字符 --> 打印

·关闭文件

==> 例子2:使用相关函数,计算一个文件的大小。

  1. 打开文件
  2. 把文件指针偏移到文件末尾
  3. 计算当前文件指针相对于文件开头的偏移量(文件大小)
  4. 关闭文件

 

标准输入输出缓冲区

为了让低速的输入输出设备与高速的用户程序能够协调工作,降低输入输出设备的读写次数,计算机在内存中预留了一定的内存空间,用来暂时保存输入输出的数据,这部分预留的空间就是缓冲区!

缓冲区分为三类!

全缓冲:在输入输出的时候只有缓冲区满了才会进行真正的输入输出操作!全缓冲的缓冲区大小是由限制的!缓冲区满了就会清空缓冲区!

行缓冲:在输入输出的时候,如果缓冲区满了或者是碰到换行符 ‘\n’ 此时就会刷新缓冲区!Printf(); scanf(); getchar(); fgets()  ....

不带缓冲:数据必须立即进行输入输出!

==> 画图分析输入输出的时候的缓冲区。

==> 验证输出缓冲区!

 

总结:printf函数想要输出数据显示在屏幕上

  1. 程序结束,输出缓冲区的数据会被全部刷新
  2. 缓冲区满,缓冲区填满了那么所有的数据都会被刷新出来
  3. 缓冲区中碰到 \n , 缓冲区的数据碰到 \n就会把数据立即刷新!

==> 不带缓冲区 ==>

标准输入 : stdin --> 带缓冲区

标准输出 : stdout --> 带缓冲区

标准出错 : stderr     --> 不带缓冲区 --> perror()

==> 把数据输出到标准出错 ==> fputs() : 把数据输出到某一个文件流指针

==> 例如:把数据输出到标准出错

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

==> s : 输出的字符串

==> stream : 输出到哪一个文件流指针 ==> stderr

把”helloworld”写入到标准出错   fputs(“helloworld”, stderr);

 

标准IO : 带缓冲的IO --> 处理大量数据的文件读写时效率比系统IO高!

系统IO : 不带缓冲的IO --> 只要有数据就会立即处理!

  • 文件属性获取
  1. stat函数  --> 获取文件属性

SYNOPSIS

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <unistd.h>

       int stat(const char *pathname, struct stat *buf);

==> pathname : 文件路径名

==> buf : 结构体指针 --> stat结构体

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

 struct stat {

               dev_t     st_dev;         /* ID of device containing file */

               ino_t     st_ino;         /* inode number */

               mode_t    st_mode;        /* protection */ //文件类型

               nlink_t   st_nlink;       /* number of hard links */

               uid_t     st_uid;         /* user ID of owner */

               gid_t     st_gid;         /* group ID of owner */

               dev_t     st_rdev;        /* device ID (if special file) */

               off_t     st_size;        /* total size, in bytes */ //文件大小

               blksize_t st_blksize;     /* blocksize for filesystem I/O */

               blkcnt_t  st_blocks;      /* number of 512B blocks allocated */

               /* Since Linux 2.6, the kernel supports nanosecond

                  precision for the following timestamp fields.

                  For the details before Linux 2.6, see NOTES. */

               struct timespec st_atim;  /* time of last access */

               struct timespec st_mtim;  /* time of last modification */

               struct timespec st_ctim;  /* time of last status change */

};

==> 例子1:使用stat函数获取一个文件的大小。

==> 例子2:使用stat函数获取文件的属性和大小。

==> Linux下的一切都是文件:

           S_IFSOCK   0140000   socket //套接字文件

           S_IFLNK    0120000   symbolic link //链接文件 --> 软链接+硬链接

           S_IFREG    0100000   regular file //普通文件

           S_IFBLK    0060000   block device //块设备文件 --> 硬盘 ...(存储类)

           S_IFDIR    0040000   directory //目录文件 (文件夹)

           S_IFCHR    0020000   character device //字符设备 (设备驱动)

           S_IFIFO    0010000   FIFO //管道文件

练习1:设计程序,实现如下功能、

==> 执行程序格式为  ./stat  <文件名>

==> 检测传入的文件名的类型,如果是普通文件,那就把文件的名字和大小输出!然后把文件的内容读取并且显示 (使用标准IO实现)

==> 如果是目录文件,那就打印”文件 xxx 是一个目录文件!”

  1. access函数 --> 检测文件是否具有某种权限

SYNOPSIS

       #include <unistd.h>

       int access(const char *pathname, int mode);

==> pathname :文件路径名

==> mode : 检测的文件权限

  F_OK  : 文件是否存在

R_OK  :文件是否可读

W_OK : 文件是否可写

          X_OK :文件是否可执行

返回值:成功(具有这种权限时)返回0,失败(不具有这种权限)返回-1

 

 ==> 例子1: 使用access函数检测文件是否存在!

==》练习2:使用access函数去测试一个文件的权限

==> 例如: 1.c是存在,可读,可写,不可执行

==> ./test2  1.c

==> 执行结果 : 输出”文件 1.c 存在 可读 可写 不可执行”

  • 目录IO

目录IO:对目录文件进行IO操作。

1, opendir() --> 打开目录文件

SYNOPSIS

       #include <sys/types.h>

       #include <dirent.h>

       DIR *opendir(const char *name);

==> name : 需要打开的目录的名字

返回值: 成功返回DIR * 目录流指针,失败返回NULL

 

 

2, readdir() --> 读取目录里面的信息 (一次只能读取一个文件的信息)

SYNOPSIS

       #include <dirent.h>

       struct dirent *readdir(DIR *dirp);

==> dirp : 目录流指针

返回值: 成功返回一个文件信息结构体指针,失败或者到目录末尾返回NULL

 On Linux, the dirent structure is defined as follows:

           struct dirent {

               ino_t          d_ino;       /* inode number */

               off_t          d_off;       /* not an offset; see NOTES */

               unsigned short d_reclen;    /* length of this record */

               unsigned char  d_type;      /* type of file; not supported

                                              by all filesystem types */

               char           d_name[256]; /* filename *///文件名长度不能超过 255个字符

           };

 

3, closedir()  --> 关闭目录流指针

SYNOPSIS

       #include <sys/types.h>

       #include <dirent.h>

       int closedir(DIR *dirp);

 ==> 例子1: 设计程序,读取指定目录下的所有文件的信息,打印文件名。

练习3:参考readdir.c ,实现对一个目录下的文件信息进行检索,打印所有的文件名。除了 “.” 和 “..”  。

思路:每次从目录中读取到一个文件信息之后,先判断文件名是不是 “.” 或者”..”如果是,那就不打印,否则就打印!

==> readdir的文件类型查看:

 

==> 例子2: 使用相关函数对一个指定的目录进行检索。并且打印文件是普通文件还是目录文件,还是其他文件。

 

练习4:设计程序,检索指定目录,记录这个目录下的普通文件数量和目录文件的数量。

==> ./readdir1  test_dir/

==> 输出信息: 目录 test_dir 中一共有 5个普通文件,2个目录文件!

==> 例子3:使用相关函数对一个指定目录进行检索,只打印其中某一种格式的文件,比如只检索BMP文件。

思路:bmp文件的特点?  ==> xxxx.bmp  ==> bmp文件的文件名后4个字符是 “.bmp”

==> 实现方案:

检索文件的时候,对文件名进行判断,如果文件名是 “.bmp”结尾的文件,那就输出,否则就不输出!

==> 如何判断文件名后4位是不是 .bmp ?

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqb_newfarmer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值