《UNIXLinux程序设计教程》一2.1 UNIX 输入输出基本概念

2.1 UNIX 输入输出基本概念

在任何一种操作系统中,程序开始读写一个文件的内容之前,必须首先在程序与文件之间建立连接或通信通道,这一过程称为打开文件。打开一个文件的目的可能是要读其中的数据,也可能是要往其中写入数据,还可能是既要读又要写数据。
UNIX系统有两种机制用于描述程序与文件的这种连接:一种称为文件描述字,另一种称为流。因此,系统中关于I/O的函数也分为两大类:一类针对文件描述字操作,另一类针对流操作。
当用流或描述字I/O函数打开一个文件时,它们分别返回一个流或文件描述字,然后便可以将这个流或文件描述字作为参数传递给相应读写函数来完成实际的读写操作。
当已完成对文件的读写之后,可以通过关闭文件而终止程序与文件的这种连接。一旦关闭了一个文件描述字或者一个流,就不能再对它进行输入输出。
1. 文件描述字与流
UNIX系统中,文件描述字表示为int类型的对象,而流表示为指向类型为FILE结构的指针。文件描述字函数多数是系统调用,它们提供底层基本的输入输出操作接口。当需要对特定设备进行控制操作时,往往必须使用文件描述字,流函数不能够进行这类操作。另外,如果程序需要按特殊方式进行输入输出(如非阻塞输入),也必须使用文件描述字。
流函数建立在文件描述字之上,通过文件描述字函数而实现,它给程序提供了更高一级的输入输出接口。流函数比对应的文件描述字函数更丰富,功能更强大,也更利于程序的移植。任何运行ANSI C的系统均支持流,但并不是所有系统都支持文件描述字,有的系统根本不支持文件描述字或仅仅实现了文件描述字函数集合的一个子集。因此,一般情况下,应当坚持使用流而不是文件描述字,除非是想做某种特殊操作,而此操作只能用文件描述字才能完成。
本章将介绍的标准I/O函数均针对流操作,第3章将介绍针对文件描述字的I/O函数。
2. 文件名与路径名
UNIX系统中几乎每一种对象都表示为文件,不仅是通常的数据集合,系统中的每一个设备也表示为文件。文件被安排在目录中,目录本身又含有子目录,由此形成了文件系统的层次结构。
目录本身也是一种文件,不过它的内容是一组连接实际文件的文件名及相关信息,这些连接称为链或目录登记项(4.2.2节)。我们前面虽然说 “文件被安排在目录中”,但是实际上目录只包含指向文件的指针而不是文件本身。为了理解文件名的语法,首先需要理解UNIX文件系统的目录层次结构。
系统中,每一个用户均有一个主目录,其文件通常存储在这个目录以及该目录的子目录中。例如,用户kjzhao,他的主目录是/home/kjzhao,在其主目录中有系统帮助建立的几个标准目录,如.bash_profile等;也有由他自己创建的子目录,如用于日常工作的目录work,用于应用程序的目录program等。另外一些用户的主目录也可能位于/home目录中,而/home则是根目录“/”的子目录。在根目录中通常还包括用于系统程序的子目录/bin,用于系统配置文件的子目录/etc,用于系统库文件的子目录/lib,以及代表各种物理设备的子目录/dev等。图2-1是这种目录层次的一个示例图。
UNIX中,当涉及一个文件的名字时,常常使用术语“文件名”或“路径名”。但按POSIX标准术语,文件名和路径名分别有不同的含义:文件名指的是不带路径的文件名,而路径名的含义则较广泛,它既包括含路径的文件名,也包括单个文件名。不过,从一般用户的角度来看,由于路径名总是用来引用文件,因此有时也不加区分地统称路径名为文件名。为了叙述方便,本节我们按POSIX标准区分路径名和文件名。在其他章节中,只要上下文含义清楚,我们也不加区分地使用路径名和文件名。
同其他操作系统一样,UNIX中每一个文件都有一个名字,此名字为一字符串,即文件名。文件名用于命名一个文件,它由1至NAME_MAX个字符组成,这些字符可以是字符集中除斜线字符(/)和空字符(NUL)之外的任意字符。系统宏NAME_MAX是POSIX定义的文件名的最大字符个数(不是字符串的长度,该计数不包括结束的空字符)。文件名也称为路径名分量。
路径名用于标识一个文件,它是由1至PATH_MAX个字符组成的字符串。路径名由用斜线“/”分隔的一至多个路径名分量构成的序列组成。路径名开始的斜线是可选的,仅由一个分量构成的路径名标识一个相对于当前目录的文件,多个连续的“/”字符等价于单个“/”字符。一个具有多个路径名分量的路径名命名一个目录以及在该目录中的文件。系统宏PATH_MAX是POSIX定义的路径名的最大字符个数,大多数现代UNIX版本中该值定为1024, Linux则没有限制。
以“/”开头的路径名称为绝对路径名,此路径名的第一个分量位于根目录;其他路径名称为相对路径名,它们的第一个分量位于当前工作目录(4.9.1节)。

路径名分量“.”和“..”有特殊的含义。“.”表示当前目录,“..”表示当前目录的父目录。作为一个例外,根目录中的“..”表示的是根目录本身。
标识一个目录的路径名可以任选地以斜线“/”结尾。可用路径名“/”来引用根目录。下面是一些路径名的例子:
/a/b 根目录下子目录a中的文件b
a 当前工作目录中名为a的文件
./a 与a相同
../a 当前工作目录的父目录中名为a的文件
与Windows操作系统不同,UNIX没有任何关于文件扩展名或文件版本的内建支持作为文件名语法的一部分。虽然许多实用程序使用有关文件名的一些约定,如C源代码文件通常具有后缀为“.c”的名字,但是,这并不意味着UNIX文件系统本身强制这类约定。
3. 文件位置
对于已打开的文件,它的属性之一是文件位置。文件位置给出文件中当前可读写字符的位置,在所有POSIX兼容的系统中,它是一个表示距文件开始多少字节数的整数。
当文件刚打开时,文件位置位于文件的开始处,之后每当读出或者写入一个字符,文件的位置便增加一字节。换言之,对文件的访问是顺序的。
但是,对于以“添加”(append)打开的文件(2.3节),其写出的处理有点特殊。对这种文件的写出总是顺序地附加在该文件的末尾,而不管文件的位置如何。其文件位置只用于控制从文件读出数据。
普通文件(4.2.1节)允许读写文件的任意位置。这种允许读写任意位置的文件也称为随机文件。可以用函数fseek()或lseek()改变随机文件的位置。如果企图改变一个不支持随机访问的文件的位置,则会得到ESPIPE错误。磁盘文件一般均是随机文件,终端则不是随机文件。
UNIX环境中,多个进程可同时读一个文件。为了使得每个进程都能够按自己的步调读文件,每个进程必须有自己的文件位置指针,这样才不会受到其他进程的影响。事实上,进程每次打开一个文件都会创建一个独立的文件位置。因此,即使在同一个程序中打开一个文件两次,也会得到两个具有独立文件位置的流或描述字。但是,如果打开一个文件描述字,然后复制它得到另一个文件描述字(3.5节),则这两个文件描述字会共享同一文件位置:改变一个文件描述字的文件位置将影响另一个描述字的文件位置。

时间: 2024-11-08 17:24:25

《UNIXLinux程序设计教程》一2.1 UNIX 输入输出基本概念的相关文章

《UNIXLinux程序设计教程》一导读

前言 十年前,我们出版了<UNIX程序设计教程>(清华大学出版社).十年来,影响UNIX编程接口的规范和标准发生了较大变化,当时写书参照的"Single UNIX Specification 2"现在已发展到了"Single UNIX Specification 4",而若干分离独立的规范和标准,包括Single UNIX Specification,现在都已经统一在POSIX.1-2008标准之下.同时,随着Linux系统的成熟和发展,UNIX系统已不

《UNIXLinux程序设计教程》一第3章-3.0 低级输入输出

第3章-3.0 低级输入输出 标准I/O函数提供了丰富.便捷的输入输出方法,但有时程序员并不需要标准I/O函数提供的数据转换和缓冲处理,而希望使用自己的方法.例如,当需要用很大的缓冲来读二进制文件,或需要对特定设备(如终端)进行控制操作,或需要传递文件描述字给子进程(子进程可以用继承的文件描述字创建自己的流,但不能直接继承流)时,便需要使用UNIX的输入输出系统调用.这些系统调用习惯上称为低级I/O函数. 低级I/O函数对文件描述字进行操作,其中有一些是实现标准I/O函数的初等函数:另外一些则执

《UNIXLinux程序设计教程》一第2章-2.0 标准输入输出

第2章-2.0标准输入输出输入输出(I/O)是任何一种编程环境中最基本的功能.本章首先讨论UNIX系统中输入输出的基本概念,然后介绍标准输入输出函数.以后各章我们将介绍更深入的输入输出概念.

《UNIXLinux程序设计教程》一第1章 UNIX导论

第1章 UNIX导论UNIX是一个"历史悠久"的操作系统.在开始讲述UNIX环境程序设计方法之前,我们先回顾UNIX的诞生.成长和发展历程,介绍UNIX发展过程中出现的若干标准.回顾UNIX的发展历史,有助于我们了解它具有如此强大生命力的原因,并把握它未来的发展方向:了解UNIX的标准,可以使我们理解和区分UNIX的不同实现与版本之间的区别,并编写出可移植性更好的程序.随后,作为后继章节的基础,本章将讲述UNIX的一些基本概念,并介绍与UNIX全系统有关的一些内容,例如系统信息.系统能

《UNIXLinux程序设计教程》一1.1 UNIX简史

1.1 UNIX简史 UNIX早在MS DOS.Windows出现之前就已经诞生了,到现在已有四十多年的历史. 1.1.1 UNIX的诞生 1965年麻省理工学院的MAC课题组和通用电气公司一起启动了一个项目-开发一个新的称为Multics的多用户.交互式操作系统.Multics的目的是向大用户团体提供同时计算和存储的能力.在当时批处理系统为主流的情况下,这是一个创新的概念.此后不久,贝尔实验室的计算科学研究中心也加入了这一计划.但在1969年,这个研究组认为开发Multics需要更长的时间,于

《UNIXLinux程序设计教程》一2.7 流缓冲

2.7 流缓冲 每一个流都有一个输入输出缓冲区.写入流的字符并不立即写到文件中,而是先在缓冲区中聚集为一块,然后异步地以块为单位传送到文件.类似地,从流读出的字符也不是逐个地从文件中读出,而是以块为单位从文件读到缓冲区,然后从缓冲区传送给进程.这种处理方式称为缓冲. 采用缓冲的目的是为了减少调用低级I/O函数(如read()和write())的次数,因为这些真正读写文件的函数是系统调用,它们是较费时间的操作.例如,对于存储在硬盘上的文件,当进程用read()或write()读写数据时,设备驱动程

《UNIXLinux程序设计教程》一3.1 文件描述字的打开、创建和关闭

3.1 文件描述字的打开.创建和关闭 函数open()或create()用于打开或创建一个文件描述字. #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char * filename, int flags [, mode_t mode]); int create (const char * filename, mode_t mode); open()用于打开或

《UNIXLinux程序设计教程》一3.2 read()和write()函数

3.2 read()和write()函数 对文件描述字进行基本输入输出操作的函数是read()和write(). #include <unistd.h> ssize_t read (int filedes, void * buffer, size_t nbytes); ssize_t write (int filedes, const void * buffer, size_t nbytes); read()从已打开的.与文件描述字filedes相连的文件中读至多nbytes个字节的数据放到b

《UNIXLinux程序设计教程》一1.2 标准

1.2 标准 UNIX变体的激增产生了许多兼容性问题,特别是各种商业UNIX变体的出现使情况变得更加复杂.系统V和BSD在许多方面不同-它们有不同且互不兼容的物理文件系统.网络机制和虚拟内存结构.这些不同中有一些限制在内核设计和实现上,但另一些出现在程序设计接口层,这导致没有一个复杂的应用程序能够不加修改地同时运行于系统V和BSD系统.另一方面,商业变体常常带有各自的增值特征,应用程序员常常搞不清它们.结果,为了保证程序在各种不同的UNIX上都能工作,程序员不得不付出极大的努力.这种情形导致了对