LINUX(UNIX)文件I/O学习(一)

一、文件描述符

  文件描述符是当打开或创建一个文件时,由内核向相应进程返回的标识(非负数,为int类型)。相应进程可以引用该标识对打开或创建的文件进行操作。

  在unistd.h中定义了3个文件描述符:

    标准输入  STDIN_FILENO  0

    标准输出  STDOUT_FILENO 1

    标准错误  STDERR_FILENO 3

二、打开/创建文件

  通常用open、creat函数来打开和创建一个文件   

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4
 5 //打开一个文件
 6 int open(const char *pathname, int flags);    
 7 返回:若成功为文件描述符,若出错为- 1
 8 //创建一个文件
 9 int open(const char *pathname, int flags, mode_t mode); 
10 返回:若成功为文件描述符,若出错为- 1
11 //以只写的方式创建一个文件
12 int creat(const char *pathname, mode_t mode);
13 返回:若成功为文件描述符,若出错为- 1

  open函数可以用来打开一个文件,同时也可以用来创建一个文件,返回文件描述符,并且该文件描述符一定为当前未用的最小的。

  pathname:将要打开或将要创建文件的名字

  flags:可以是一下的值或运算后的结果(注:前三个只能选一个)

    O_RDONLY    --以只读的方式打开文件

    O_WRONLY    --以只写的方式打开文件

    O_RDWR     --以可读可写的方式打开文件

    O_APPEND    --以在文件尾追加的方式打开文件

    O_CREAR     --若文件不存在则创建它,并且指明第3个参数mode

    O_EXCL      --若同时指明了O_CREAT时,若文件已存在则报错,若不存在则创建文件(检测与创建绑定在一起为原子操作)

    O_TRUNC    --如果此文件存在,而且为自读或只写打开,则将其长度截断为0  

    O_NOCTTY     --如果p a t h n a m e指的是终端设备,则不将此设备分配作为此进程的控制终端。  

    O_NONBLOCK  -- 如果p a t h n a m e指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的 I / O操作设置非阻塞方式。

    O_SYNC     --使每次w r i t e都等到物理I / O操作完成。
    O_SYNC    --选择项不是P O S I X . 1的组成部分,但S V 保证在一个给定的描述符

  mode:

  对于creat函数,由于creat函数是已只写方式创建一个文件所以

  creat(pathname, mode)等于open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)  

三、关闭文件

  用close函数关闭文件  

1 #include <unistd.h>
2
3 int close(int fd);

  指定相应的文件描述符就可以关闭打开的文件

四、当前文件位移量(针对打开过的文件)

  打开的文件都有一个与该文件相关联的当前文件位置,当进行I/O操作时,就从该位置开始。lseek用来重新定位文件中的当前位置(也可以返回当前文件的位置)。

  由于lseek的以前的返回类型以及offset都是long类型,因此为lseek

1 #include <sys/types.h>
2 #include <unistd.h>
3
4 off_t lseek(int fd, off_t offset, int whence);

  fd:相应文件描述符

  offset:在文件中相对与whence的位移量

  whence:标识在文件中的特定位置,有3个值

    SEEK_SET:指文件开头

    SEEK_CUR:指当前文件的位置

    SEEK_END:指文件的尾

  lseek(fd, 0, SEEK_CUR)用来返回文件的当前位置。

  对与刚刚打开的文件一般是返回0,当以O_APPEND打开时,返回的为非零,为文件尾。

  如果用lseek函数修改的当前位移量超过文件的当前长度时,该文件会形成文件空洞,文件空洞是不占用磁盘空间的,但是当读文件时,会将文件空洞读作0。

五、I/O操作

  I/O操作包括对文件的读写操作,因此用到了read,write函数

1 #include <unistd.h>
2
3 ssize_t read(int fd, void *buf, size_t count);
4
5 ssize_t write(int fd, const void *buf, size_t count);

  fd:相应文件的文件描述符

  buf:读/写的缓冲区

  count:对read,为要读的字节数,对write,为buf的大小  

  对read:  

  当读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之前还有3 个字节,而要求读 10个字节,则read返回3,下一次再调用re ad时,它将返回0 (文件尾端)。也就是说当读到文件尾是,最后一次读一定是返回0。

  当从终端设备读时,通常一次最多读一行。
  当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
  某些面向记录的设备,例如磁带,一次最多返回一个记录。

  对write:

  write出错原因:

    1.磁盘满

    2.超出了文件长度的限制

  write,read后都会修改文件的当前位移

六、内核中与文件相关的3个数据结构

  在操作系统内核中维护这文件的相关信息,他们的关系如下:

  操作系统为维护进程,设定了一个进程表,每一个进程在进程表中都单独占一个记录项

  每个进程为维护打开的文件,设定一个文件描述符表(1),没一个文件描述符在该表中单独占一个记录,并且一个记录由两项组成:

    1.文件描述符标志

    2.指向文件表的指针

  文件表中又包括了3项

    1.文件状态标志(O_RDONLY | O_WRONLY...)

    2.文件的当前位移(参见四、文件的当前位移量)

    3.指向v节点的指针(v节点,文件的虚拟文件系统)

  v节点包括的信息

    1.v节点的信息

    2.i节点的信息

    3.文件的长度

  当两个相互独立的进程打开同一个文件时,他们各自会分别获得一个文件描述符表,一个文件表,但是文件表中的v节点指针会指向同一个v节点。

  此时当值进行文件读时,两个进程各不相干,都能正常进行,这是因为两个进程都有一个独立的文件表(包含一个文件当前的位移量,这个仅属于当前进程)。当进行文件写时,可能发生问题,例如,当打开文件时两个进程(A,B)的都将文件的当前位移量置为0,此时进程A先对该文件写如1000个字节,写过后,更改文件的当前位移量为1000,以及文件的长度为1000,此时进程B对该文件进行写(注意此时对B进程来说文件的当前位移量并没有变还是0),此时B进程写过1000个字节后恰好覆盖了A进程写入的,造成了写覆盖。

  当然这个问题是可以解决的,只要在open文件时添加O_APPEND就能解决,因为这个标志规定将这两个操作(1.将文件表的文件当前位移量设为文件尾2.对文件写)作为原子操作,即每次写文件时,都会先修改文件的当前位移量为文件尾。这就是进程件文件共享的一个例子。

  另外原子操作指的是将多个步骤的操作看成一个步骤,要么全做,要么不做。

七、改变打开文件的性质

  要该变文的性质要用到fcntl,或者dup,dup2)(fcntl可以替代dup,dup2)

1 #include <unistd.h>
2 #include <fcntl.h>
3
4 int fcntl(int fd, int cmd, ... /* arg */ );

  fd:相应文件描述符

  cmd:用来确定fcntl的功能可以为下面的值

    F_DUPFD:复制文件描述符

    F_GETFD/F_SETFD:获得/设置文件描述符标志

    F_GETFL/F_SETFL:获得/设置文件状态标志

    还有其他,不过先学这几个

  ...:在ANSCI C中表示可以更多的参数

  fcntl的功能:

  正如cmd列出的,已个标志代表一个功能

  1.复制文件描述符

    复制描述符可以用dup,dup2,fcntl。

    复制文件描述符后,使得新文件描述符和原有的文件描述符共享一个文件表,但是各自独占已个文件描述符表

1 #include <unistd.h>
2
3 int dup(int oldfd);
4 int dup2(int oldfd, int newfd);

    newfd = dup(oldefd);   等同于  newfd = fcntl(oldfd, F_DUPFD);

    dup2(oldfd, newfd);  等同于

    close(newfd);

    fcntl(oldfd, F_DUPFD, newfd);

    只是dup2为原子操作

    dup2操作是,制定newfd为新的文件描述符,如果newfd已经打开了则先关闭在复制。 

   2.获得/设置文件描述符标志(目前仅仅有已一个标志位close_on_exec)及FD_CLOEXEC    

    用dup,dup2,fcntl复制文件描述符时,该值会被清除。

    设置F_GETFD会获得FD_CLOEXEC的值(以函数返回值返回)

    设置F_SETFD会将...参数的值设置给FD_CLOEXEC位(用到第3个参数)

   3.获得/设置文件状态标志

    设置F_GERFL会以函数返回值的形式返回文件的状态标志

    由于O_RDONLY,O_WRONLY,O_RDWR只能设置一个,所以要先将返回值与O_ACCMODE相与再来判断是3个值的哪一个

    而其他标志这不需要

    设置F_SETFL会将函数的第三个参数的值赋给文件的状态标志

时间: 2024-10-11 22:43:07

LINUX(UNIX)文件I/O学习(一)的相关文章

Linux Unix shell 编程指南学习笔记(第一部分)

第一章:文件安全与权限: 1.文件和目录的权限 创建文件时系统保存了文件所有相关的信息,包括 文件的位置 . 文件类型 . 文件长度 . 哪位用户拥有该文件,哪些用户可以访问该文件 . i 节点 . 文件的修改时间 . 文件的权限位 . 文件类型: d: 目录 l : 符号链接(指向另一个文件) s: 套接字文件 b: 块设备文件 c: 字符设备文件 p: 命名管道文件 -: 不属于上述类型的文件 文件权限 XXX       XXX        XXX 最左边 XXX : 文件属主 权限位

Linux Unix shell 编程指南学习笔记(第五部分)

第二十五章 深入讨论 << 当shell 看到 << 的时候,它知道下一个词是一个分界符,该分界符后面的内容都被当做输入,直到shell又看到该分界符(位于单独的一行).比如: cat >> tmpfile <<DOC > this is the first line > this is the second line > third > forth >..... >DOC 其中DOC就是分界符,再次在新的行中输入DOC时

Linux Unix shell 编程指南学习笔记(第四部分)

第十六章  shell脚本介绍 此章节内容较为简单,跳过. 第十七章   条件测试 test命令 expr命令 test  格式  test  condition     或者  [ condition ]  (注意: condition两侧有空格) 文件状态测试: - d 目录 : - s 文件长度大于0.非空 : - f 正规文件 - w 可写 : - L 符号连接 : - u 文件有s u i d位设置 - r 可读 : - x 可执行 测试的逻辑操作符: -a   :逻辑与,操作符两边均

Linux Unix shell 编程指南学习笔记(第三部分)

第十三章  登陆环境 登陆系统时,输入用户名和密码后,如果验证通过,则进入登录环境. 登录过程 文件/etc/passwd $HOME.profile 定制$HOME.profile /etc/passwd 文件解析(抽取其中的一行作为示例): 1 2 3 4 5 6 7 root: <span style="white-space:pre"> </span>x: 0: 0: root: <span style="white-space:pre&

Linux对文件内容基本操作(学习笔记七)

一.cat 1.1.查看文件内容 格式:cat 文件名 [[email protected] /]# cat /etc/resolv.conf # Generated by NetworkManager nameserver 10.198.1.1 nameserver 8.8.8.8 [[email protected] /]# 但是当文件内容比较多,超过一屏时,cat命令就不能满足查看要求,就要用到more|less来查看 1.2.重定向输入文件内容到新的文件 [[email protecte

Linux Unix shell 编程指南学习笔记(第二部分)

第七章  正则表达式介绍 匹配行首与行尾 匹配数据集 职匹配字母和数字 句点 "." 匹配任意单字符. ^,在行首 匹配字符串或字符序列,如查询当前目录下的所有目录: ls -l | grep "^d" 在行尾以 "$"匹配字符串或字符  , 匹配所有以sh结尾的行: sh$ 匹配所有的空行: ^$ 使用*匹配字符串中单字符或重复序列: skdf*jl 使用 \ 转义特殊字符的含义: 特殊字符:   $  .   ''  '   *  [  ]

Linux学习笔记四:Linux的文件搜索命令

1.文件搜索命令  which 语法:which [命令名称] 范例:$which ls  列出ls命令所在目录 [[email protected] ~]$ which ls alias ls='ls --color=auto' /bin/ls 另外一个命令:whereis [名称名称],也可以列出命令所在目录. [[email protected] ~]$ whereis ls ls: /bin/ls /usr/share/man/man1/ls.1.gz /usr/share/man/ma

UNIX/Linux下C语言的学习路线

一.工具篇 “公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工具. 1.操作系统    在UNIX或Linux系统中学习C很方便,所以在开始您的学习旅程前请先选择一个UNIX或Linux操作系统,目前可供个人免费使用的UNIX或Linux系统有FreeBSD.RedHat Linux.SUSE Linux等,而且在安装包中还提供很多实用的工具,如:gcc, make等. 如果您一直使用Window

《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)

<Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h>文件中的常量. 通过cat 命令查看: [email protected]:~/Code/tlpi$ cat /usr/include/limits.h /* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005 Free Software

《Linux/Unix系统编程手册》读书笔记8 (文件I/O缓冲)

<Linux/Unix系统编程手册>读书笔记 目录 第13章 这章主要将了关于文件I/O的缓冲. 系统I/O调用(即内核)和C语言标准库I/O函数(即stdio函数)在对磁盘进行操作的时候都会发生缓冲.通过缓冲可以在一定程度上将用户空间与实际的物理设备分离,还可以减少内核访问磁盘的次数. 先来看看关于内核缓冲区高速缓冲:read和write调用在对磁盘文件进行操作的时候不会直接访问磁盘,如下图所示. 例如:write(fd, "abc", 3) write调用会将"