unix-like(后面以linux为例)系统中的文件操作只需要五个函数就足够了,open、close、read、write以及lseek。这些操作被称为不带缓存的io,这里有必要说一下带缓存和不带缓存的操作的区别。不带缓存的io是相对于带缓存的io的来说的,带缓存的io有哪些呢。在后面的fwrite、fread函数等标准io操作都是带缓存的io。说了这么多还是没有说清楚带缓存和不带缓存的区别,下面就以write函数和fwrite函数来说明带缓存和不带缓存的区别。虽然write函数叫做不带缓存的io,但是当write函数向文件中写入数据时,会先将数据写入到内核的一个缓冲区中,注意这个缓冲区是由内核提供的,当内核的缓冲区填满以后,内核将缓冲区中的数据排队到输出队列的末端,然后由内核相应的功能将输出队列的数据输出到磁盘,所以write函数还是有缓冲的,我们也将write函数称作系统调用。下面介绍了fwrite函数之后就可以理解为什么write函数叫不带缓存的函数。fwrite函数是对write函数封装的结果。在封装时,在用户的层面上提供了一些缓冲区,当向文件中写入数据时,只有当用户层面的缓冲区填满时,才会将这些缓冲区中的数据写入到内核的缓冲中。这样就可以理解带缓存的io和不带缓存的io,这都是相对于用户层面而言的。

在linux系统中,为每一个打开的文件分配一个文件描述符。所有的程序都打开了三个文件,标准输入,标准输出和标准出错。这三个文件的描述符分别为0,1,2,或者分别用宏定义STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO来表示。当打开一个其它非标准输入输出文件时,则返回一个系统中尚未使用的编号最小的文件描述符,当然这个描述符必定是大于或者等于3的。

open函数用来打开一个文件,它的函数原型是:

int open(const char* pathname,int oflag,...);

第一个参数是用来指定所要打开的文件的路径和名字,第二个参数用来指定文件的打开方式,第三个参数...表示后面可以有任何类型的任意多个参数,不过第三个参数只有在用open函数创建新文件时才用来指定新建文件的权限。第二个参数可以有的选择有:

O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以可读可写的方式打开文件

实际上面的三种选择的值分别为0,1和2。在初学linux编程时比较容易犯的一个错误是,文件以可读可写方式打开时,写成如下的形式:

int fd = open("filename" , O_RDONLY | O_WRONLY);

O_RDONLY | O_WRONLY表示将两个宏按位进行或运算,所以这两个的运算就是 0 | 1 ,结果是1,也就是文件是按照只写的方式打开的,并不是按照可读可写的方式打开的。另外初学者还有一个疑惑,就是当文件以O_WRONLY只写方式打开时,能不能读呢?我当时就这么想,既然都可以向文件里面写数据了,为什么不能从文件中读呢?后来,我发现问题其实很简单,只是我将“读”理解错了,这里的读是机器读而不是人在读。显然当文件以只写的方式打开时,是不能将文件的内容从文件读到计算机中的。上面三种对文件的打开方式是互斥的,即三者只能存在其一。还有一些和上面三个参数进行搭配的选择,包括:O_APPEND、O_CREAT 、O_TRUNC 、O_EXCL 、O_NOCTTY 、O_NONBLOCK等,后面的这几个选项可以和前面的三个选择以按位或的方式并存。open函数如果调用成功,则返回打开文件的描述符,如果出错则返回-1,linux系统返回的文件描述符是系统尚未使用的最小的文件描述符。

creat函数的作用是创建一个新的文件,它的函数原型是:

int creat(const char* pathname,mode_t mode);

第一个参数用来指定要创建的文件的路径和名字,第二个参数用来指定创建文件的相关权限信息。creat创建的文件只能进行写操作,它相当于:

open("filename",WRONLY | O_TRUNC | O_CREAT,mode);

由于creat函数创建的文件只能向其中写入数据,所以如果需要读时,需要用以下的方式创建文件:

open("filename",O_RDWR | O_CREAT | O_TRUNC,mode);

creat函数如果调用成功,则返回打开文件的描述符,如果出错则返回-1。

close函数用来关闭打开的文件,它的函数原型是:

int close(int filedes);

它的参数是一个文件描述符,如果调用成功,则返回0,否则返回-1。

lseek函数用来设置文件指针的位置,它的函数原型是:

off_t lseek(int filedes,off_t offset,int whence);

第一个参数为打开的文件描述符,第二个参数是相对于第三个参数的偏移量,第三个参数是一个标记。第三个参数有三种选择,分别是:

SEEK_SET:表示从文件起始位置开始
SEEK_CUR:表示从当前文件指针位置开始
SEEK_END: 表示从文件末尾开始

对于SEEK_SET来说,第二个参数偏移量只能为非负值,对于SEEK_CUR来说,第二个参数偏移量可正可负,对于SEEK_END来说,偏移量也是可正可负。如果SEEK_END,偏移量为正数时,会将文件指针,从当前文件末尾向后移动,中间掠过的位移填充为空,这种文件称为空洞文件。lseek如果成功返回,则返回当前文件指针的位移,如果出错则返回-1。在有些特殊的文件中,文件指针的位移允许为负值,所以,如果判断lseek是否执行成功,最好用返回值是否为-1来进行判断。

read函数用来从一个已打开的文件中读取文件的内容,它的函数原型是:

ssize_t read(int filedes,void* buff,size_t nbytes);

第一个参数是一个已打开的文件的描述符,第二个参数是一个缓冲区的指针,第三个参数是期望一次读出多少数据。这个函数的作用是每次将文件的内容读取到缓冲区buff中,如果执行成功,则返回所读取的实际字节数,如果失败,则返回-1,如果到达文件末尾,则返回0。

write函数用来向文件中写入数据,它的函数原型是:

ssize_t write(int filedes,const void* buff,size_t nbytes);

第一个参数是一个文件描述符,第二个参数是一个缓冲区的首地址,第三个参数是将要写到文件中的字节数。这个函数解释为向filedes中写入缓冲区buff的前nbytes个数据。如果执行成功,则返回实际写入到文件中的字节数,如果失败则返回-1。

文件io(一)--unix环境高级编程读书笔记相关推荐

  1. 标准IO库--unix环境高级编程读书笔记

    标准IO库是C语言提供的一个库,不光存在于linux中,在windows中也是有的.标准IO库和文件IO的不同是,标准IO库是对文件IO(即系统调用)的封装,并且在用户层添加了一些缓冲区. 文件IO的 ...

  2. linux系统数据文件和信息--unix环境高级编程读书笔记

    linux系统中的数据文件有很多,在这一章里介绍的主要内容是和系统有关的一系列文件,包括passwd,shadow,group,utmp,wtmp以及一些系统的相关信息和时间的相关操作. 1.pass ...

  3. 文件和目录(二)--unix环境高级编程读书笔记

    在linux中,文件的相关信息都记录在stat这个结构体中,文件长度是记录在stat的st_size成员中.对于普通文件,其长度可以为0,目录的长度一般为1024的倍数,这与linux文件系统中blo ...

  4. 高级IO(一)--UNIX环境高级编程读书笔记

    在前面学习了文件IO,标准IO和终端IO,现在学习高级IO,UNIX中怎么有这么多的IO. 1.非阻塞IO 可以将系统调用分为两类:低速系统调用和其他.低速系统调用是可能会使进程永远阻塞的一类系统调用 ...

  5. unix进程的环境--unix环境高级编程读书笔记

    1.进程的启动 进程总是从   main   函数开始执行的,main函数的函数原型如下: int main(int argc,char* argv[]); 当内核启动  c   程序时,使用一个   ...

  6. linux进程控制(一)--unix环境高级编程读书笔记

    1.进程PID和特殊的3个进程 每一个进程在系统中都有一个唯一的标识,这个标识叫做进程标识符,或者叫  PID(process identity).我们可以通过调用  getpid  函数来获取一个进 ...

  7. linux信号(二)--unix环境高级编程读书笔记

    1.信号集 在linux中,可以用一个称为信号集的数据类型  sigset_t,来表示所有的被阻塞信号的一个集合.对这个集合的操作函数有: #include <signal.h>int s ...

  8. APUE Unix环境高级编程读书笔记

    .. 转载于:https://www.cnblogs.com/solitrarychen/p/5407536.html

  9. linux信号(一)--unix环境高级编程读书笔记

    1.信号的概念 在这里要给出一个信号的准确概念感觉很困难,可以这么说,信号就是进程之间或者内核与进程间异步通信的一种机制,有点类似于中断的性质.在  linux  系统中有  31  种信号,每一种信 ...

最新文章

  1. php做gui,php7 图形用户界面GUI如何开发
  2. 写了一个puppet web 管理界面,打算开源
  3. 九大排序算法,你会几个?
  4. 如何通过github提升自己
  5. cli2弃用了吗 vue_vue-cli 3 和 vue-cli 2的区别
  6. 关于进程与线程,史上最浅显易懂的一个简单解释!
  7. nacos在windows下安装
  8. 全民加速节:解读CDN的应用场景与产品价值
  9. 从源码分析创建线程池的4种方式
  10. C语言如何动态分配空间:malloc
  11. [转载]C++ 中有符号类型到无符号类型的转换(C和C++程序员面试秘笈P9面试题6)...
  12. 深度学习2.0-5.tensorflow的基础操作之前向传播(张量)实战
  13. ubuntu下OpenPose的安装、使用、初步介绍
  14. 第四季-专题14-串口驱动程序设计
  15. 高德地图开发(二)加载瓦片数据
  16. WPF实现照片墙拼图展示特效
  17. Ubuntu18.04调整字体大小
  18. 雷总:我也想做高级工程师 !
  19. 关于旅游景点主题的HTML网页设计——青岛民俗 7页 带登录注册
  20. 终结拖延症——行动的理由

热门文章

  1. #语音信号处理基础(十一)——梅尔倒谱系数的提取
  2. [转载] 说说 Python 字典结构的 get() 方法
  3. [转载] python字典类方法
  4. [转载] Python利用openpyxl模块读取excel文件内容
  5. 用反射实现简单的框架
  6. Effective C++条款05:了解C++默默编写并调用哪些函数
  7. BZOJ 4033: [HAOI2015]树上染色
  8. Spring(三)Bean继续入门
  9. poj 1459-Power Network解题报告
  10. 数据导出到excel文件给客户端下载的几种方法