阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Linux 中必须要了解的命令操作

69次阅读
没有评论

共计 6201 个字符,预计需要花费 16 分钟才能阅读完成。

导读 文件是 linux 中的一个重要概念。在 Linux 中,一切(几乎一切)都是文件。简单的说,C 中基本的的 printf()函数,scanf()函数,其实都属于文件操作。

对于文件操作,虽然都是通过函数调用的方式实现,却还是能分为两类:系统调用和库函数。

这篇文章将先介绍 Linux 中文件的概念,系统调用和库函数的概念,然后具体的讨论两种方式下的文件操作。

博文的主要内容如下:

  1. Linux 中的文件
  2. 文件访问-库函数
  3. 文件访问-系统调用
  4. 库函数
  5. 标准 I/O 库
  6. /proc 文件系统
Linux 中的文件
概念

按照普通的定义,文件不过是一堆数据,在往下说,就是存储器中的 010101… 而我们这里讨论的文件有了更广的定义。对于 Linux 中的文件,我的理解是:

Linux 中的文件具有的特点是:可通过操作系统或者程序对外提供信息,也能对内输入信息,可以被创建,删除。

Linux 中,文件有特别重要的意义,他们为操作系统和设备提供了一个简单而统一的接口。在 Linux 中,几乎一切都可以看做是文件。

这就意味着,普通程序完全可以像使用文件(普通定义)那样使用磁盘文件、串行口、打印机和其他设备。

硬件设备在 linux 操作系统中也被表示为文件。例如,可以通过如下命令把 cd-rom 驱动器挂载为一个文件,

#mount -t iso9660 /dev/hdc /mnt/cdrom

#cd /mnt/rom

然后,就能像访问普通文件那样在 cd-rom 目录中漫游。

操作

和操作一般意义上的文件一样,linux 中对文件的操作只需要五个基本的函数:

open、close、read、write 和 ioctl

通过调用这几个函数就能对 Linux 中的文件进行读、写等操作。不过,这种操作又分为系统调用和库函数调用。简单的说,系统调用是最直接的方式,

库函数调用最终也是通过系统调用实现的。可认为库函数调用是对系统调出于效率考虑而做出的优化。

库函数调用和系统调用的区别和联系请参看:linux 系统调用和库函数调用的区别

我们用很少的函数就可以对文件和设备进行访问和控制。这些函数就是所谓的系统调用,由操作系统直接提供,他们是通向操作系统本身的接口。

操作系统的核心部分,既内核,其实就是一组设备驱动程序。这是一些对硬件进行控制的接口。

文件访问-系统调用

通过系统调用来访问文件是最直接的方式。系统调用函数直接作用于操作系统内核的设备驱动程序从而实现文件访问。

文件描述符

在系统中需要处理的文件(读、写操作)需要一个标识,以便在其它地方能识别出这个文件,于是就产生了文件描述符。文件描述符是一些小值整数,简单的说就是

一个文件ID用于在系统中唯一的标识文件。文件描述符的总数也就是系统可以打开文件的最多个数,这取决于系统的配置情况。

当开始运行程序时,也就是系统开始运行时,它一般会有三个已经打开的文件描述符。他们是:

  • 0:标准输入
  • 1:标准输出
  • 2:标准错误

其它文件的文件描述符,在调用文件打开函数open时返回。这就是说,每个设备对应着一个文件描述符。文件描述符由操作系统分配,每次分配最小的。

write 系统调用

write,就是把缓冲区的数据写入文件中。注意,这里的文件时广泛意义的文件,比如写入磁盘、写入打印机等等。

Linux 中 write()的函数原型:

size_t write(int fildes, const void *buf, size_t nbytes);

参数说明:

fildes:文件描述符,标识了要写入的目标文件。例如:fildes 的值为 1,就像标准输出写数据,也就是在显示屏上显示数据;如果为 2,则想标注错误写数据。

*buf:待写入的文件,是一个字符串指针。

nbytes:要写入的字符数。

函数返回值:size_t  返回成功写入文件的字符数。需要指出的是,write 可能会报告说他写入的字节比你所要求的少。这并不一定是个错误。在程序中,你需要检查

error 已发现错误,然后再次调用 write 写入剩余的数据。

请看下面的例子:

Linux 中必须要了解的命令操作

运行结果:

Linux 中必须要了解的命令操作

这个程序只在标准输出上显示一条消息。

read 系统调用

系统调用 read 是从文件中读出数据。要读取的文件用文件描述符标识,数据读入一个事先定义好的缓冲区。他返回实际读入的字节数。

Linux 中 read 的函数原型:

size_t read(int fildes, void *buf, size_t nbytes);

参数说明:

fildes:文件描述符,标识要读取的文件。如果为 0,则从标准输入读数据。类似于 scanf()的功能。

*buf:缓冲区,用来存储读入的数据。

nbytes:要读取的字符数。

返回值:size_t 返回成功读取的字符数,它可能会小于请求的字节数。

Linux 中必须要了解的命令操作

运行结果:

Linux 中必须要了解的命令操作

open 系统调用

系统调用 open 的作用是打开一个文件,并返回这个文件的描述符。

简单地说,open 建立了一条到文件或设备的访问路径。如果操作成功,它将返回一个文件描述符,read 和 write 等系统调用使用该文件描述符对文件或

设备进行操作。这个文件描述符是唯一的,他不会和任何其他运行中的进程共享。如果两个程序同时打开一个文件,会得到两个不同的问价描述符。如果

同时对两个文件进行操作,他们各自操作,互补影响,彼此相互覆盖(后写入的覆盖先写入的)为了防止文件按读写冲突,可以使用文件锁的功能。这不是

本次重点,以后介绍。

Linux 中 open 的函数原型有两个:

int open(const char *path, int oflags);

int open(const char *path, int oflags, mode_t mode);

参数说明。

path:准备打开的文件或设备名字。

oflags:指出要打开文件的访问模式。open 调用必须指定如下所示的文件访问模式之一:

Linux 中必须要了解的命令操作

open 调用哈可以在 oflags 参数中包括下列可选模式的组合(用”按位或“操作):

  • O_APPEDN: 把写入数据追加在文件的末尾。
  • O_TRUNC: 把文件长度设为零,丢弃以后的内容。
  • O_CREAT: 如果需要,就按参数 mode 中给出的访问模式创建文件。
  • O_EXCL: 与 O_CREAT 一起调用,确保调用者创建出文件。使用这个模式可防止两个程序同时创建一个文件,如果文件已经存在,open 调用将失败。

关于其他可能出现的 oflags 值,请看考 open 的调用手册。

mode:

当使用哦、O_CREAT 标志的 open 来创建文件时,我们必须使用三个参数格式的 open 调用。第三个参数 mode 是几个标志按位 OR 后得到的。他们是:

  • S_IRUSR: 读权限,文件属主。
  • S_IWUSR: 写权限,文件属主。
  • S_ IXUSR: 执行权限,文件属主。
  • S_IRGRP: 读权限,文件所属组。
  • S_IWGRP: 写权限,文件所属组。

。。。。

请看下面例子:

open(”myfile”, O_CREAT, S_IRUSR|S_IXOTH ;

他的作用是创建一个名为 myfile 的文件,文件属主拥有读权限,其他用户拥有执行权限,且只有这些权限。

Linux 中必须要了解的命令操作

运行结果:

Linux 中必须要了解的命令操作

程序创建了一个名为 myfile 的文件,文件属主有读权限,其他用户有执行权限,且只有这些权限。

close 系统调用

close 系统调用用于“关闭”一个文件,close 调用终止一个文件描述符 fildes 以其文件之间的关联。文件描述符被释放,并能够重新使用。

close 成功返回 1,出错返回 -1.

#Include<unistd.h>

int close(int fildes);

ioctl 系统调用

ioctl 提供了一个用于控制设备及其描述符行为和配置底层服务的接口。终端、文件描述符、甚至磁带机都可以又为他们定义的 ioctl,具体

细节可以参考特定设备的使用手册。

下面是 ioctl 的函数原型

#include<unistd.h>

int ioctl(int fildes, int cmd,,,,,,);

ioctl 对描述符 fildes 指定的对象执行 cmd 参数中所给出的操作。

其他和文件管理有关的系统调用

还有许多其他的系统调用能对文件进行操作。

几个常用的如:lseek()对文件描述符 fildes 指定文件的读写指针进行设置,也就是说,它可以设置文件的下一个读写位置。

fstat,stat,lstat 是和文件描述符相关的函数操作,这里就不做介绍。

dup,dup2 系统调用。dup 提供了复制文件描述符的方法,使我们能够通过两个或者更多个不同的文件描述符来访问同一个文件。这可以用于

在文件的不同位置对数据进行读写。

库函数

在输入、输出操作中,直接使用系统调用效率会非常底。具体原因有二:

  • 1. 系统调用会影响系统性能。与函数调用相比,系统调用的开销大。因为在执行系统调用的时候,要切换到内核代码区执行,然后再返回用户代码。这必然就需要大量的时间开支。一种解决办法是:尽量减少系统调用的次数,让每次系统调用完成尽可能多的 任务。例如每次系统调用写入大量的字符而不是单个字符。
  • 2. 硬件会对系统调用一次能读写的数据块做一定的限制。例如,磁带机通常的写操作数据块长度是 10k,如果缩写数据不是 10k 的整数倍,磁带机还是会以 10k 为单位绕磁带,这就在磁带上留下空隙。

为了提高文件访问操作的效率,并且使得文件操作变得更方便,Linux 发行版提供了一系列的标准函数库。他们是一些由函数构成的集合,你可以在自己的程序方便的中使用它们,

去操作文件。提供输出缓冲功能的标准 I / O 库就是这样的例子。你可以高效的写任意长度的数据块,库函数则在需要的时候安排底层函数调用(系统调用)

也就是说,库函数在用户和系统之间,增加了一个中间层。如下图所示:

Linux 中必须要了解的命令操作

库函数是根据实际需要而包装好的系统调用,用户可在程序中方便的使用库函数,如标准 I O 库(稍后会讲)

标准 I / O 库

标准 I / O 库及其头文件 <stdio.h> 为底层 I / O 系统调用提供了一个通用的接口。这个库现在已经成为 ANSI 标准 C 的一部分,而前面所讲的系统调用却不是。

标准 I / O 库提供了许多复杂功能的函数,用于格式化输出和扫描输入,它还负责满足设备的缓冲需求。

在许多方面,使用标准 I / O 库和使用底层文件描述符类似。需要先打开一个文件,已建立一个文件访问路径(也就是系统调用中的文件描述符)

在标准 I / O 库中,与文件描述符对应的叫 流(stream),它被实现为指向结构 FILE 的指针。

在启动程序时,有三个文件流是自动打开的。他们是:

  • stdin: 标准输入
  • stdout: 标准输出
  • stderr: 标准错误输出

下面会介绍一些常用的 I / O 库函数:

fopen 函数

fopen 函数类似于系统调用中的 open 函数。和 open 一样,它返回文件的标识符,只是这里叫做流(stream),在库函数里实现为一个指向文件的指针。

如果需要对设备的行为进行明确的控制,最好使用底层系统调用,因为这可以避免使用库函数带来的一些非预期的副作用,如输入 / 输出缓冲。

函数原型:

#include<stdio.h>

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

参数说明:

*filename:打开文件的文件名

*mode:打开的方式

r 以只读方式打开文件,该文件必须存在。

r+ 以可读写方式打开文件,该文件必须存在。

rb+ 读写打开一个二进制文件,允许读数据。

rw+ 读写打开一个文本文件,允许读和写。

w 打开只写文件,若文件存在则文件长度清为 0,即该文件内容会消失。若文件不存在则建立该文件

w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。

fopen 在成功是返回一个非空的 FILE * 指针。失败返回 NULL

fread/fwrite 函数

fread 函数从文件流中读取数据,对应于系统调用中的 read;fwrite 函数从文件流中写数据,对应于系统调用中的 write

函数原型:

#include<stdio.h>

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

参数说明:

*ptr 要读取数据的缓冲区,也就是要存放读取数据的地方。

size:指定每个数据记录的长度。

nitems:计数,给出要传输的记录个数。

返回值:成功读取到数据缓冲区的记录个数,当到达文件尾时,他的返回值可能会消耗与 nitems,甚至可以是 0

size_t  fwrite(const coid *ptr, size_t size , size_t nitimes, FILE *stream);

他从指定的数据缓冲区 ptr 中把数据写入文件流,返回成功写入的记录个数。

fclose 函数

fclose 函数关闭指定的文件流 stream,这个操作会使所有未写出的数据都写出。因为 stdio 库函数会对数据进行缓冲,所有调用 fclose 函数是很重要的。

如果程序需要确保数据已经全部写出,就应该调用 fclose 函数。虽然程序正常结束时,也会自动的调用 fclose 函数,但这样就不能检测出调用 fclose 所产生的错误了。

函数原型如下:

#include<stdio,h>

int fclose(FILE *stream);

fflush 函数

fflush 函数的作用是把文件流中所有未写出的数据全部写出。处于效率考虑,在使用库函数的时候会使用数据缓冲区,当缓冲区满的时候才进行写操作。使用 fflush 函数

可以将缓冲区的数据全部写出,而不关心缓冲区是否满。fclose 的执行隐含调用了 fflush 函数,所以不必再 fclose 执行之前调用 fflush。

函数原型:

#include<stdio.h>

int fflush(FILE *stream);

/proc 文件系统

Linux 将一切看做文件,硬件设备在文件系统中也有相应的条目。/dev 目录中的文件使用底层系统调用这样一种特殊方式来访问硬件。

/proc 文件系统,可以看做是一个特殊的文件系统,在这个系统中,每个文件都对应一个独立的硬件,所以用户可以通过 proc 文件系统像访问文件一样来访问硬件设备。

该文件系统通常表现为 /proc 目录。该目录中包含了许多特殊文件以允许对驱动和内核信息进行高层访问。

如果你想知道 CPU 的信息,内核版本信息等,就可以通过 proc 文件系统。

/proc 目录中的文件会随系统的不同而不同。我的电脑上的 /proc 中的文件如下所示:

Linux 中必须要了解的命令操作

在多数情况下,直接读取这些文件就可以获得状态信息。

访问设备信息

例如,获取 CPU 的信息:

Linux 中必须要了解的命令操作

内存使用信息 (只显示里局部~):

Linux 中必须要了解的命令操作

每次读这些文件的内容时,他们所提供的信息都会及时更新。所以再读一次 meminfo 文件会得到不同的结果。

由特定内核函数给出的更多信息可以在 proc 目录的子目录中查到。

查看内核函数给出的信息

例如:查看网络套接字的使用统计:

Linux 中必须要了解的命令操作

通过 proc 查看进程信息

用 ps 命令可得到当前正在运行的进程,每个进程在 proc 中都有相应的信息文件,通过查看这个文件,可以得知进程相关的信息:

Linux 中必须要了解的命令操作

进程 2754 的当前工作目录是:/hme/yyl

程序 /bin/su 正在运行,还有其他信息此处不再说明;

修改 proc 文件系统内容

例如,系统中所有运行的程序同时打开的文件总数是 Linux 内核的一个参数。

Linux 中必须要了解的命令操作

如果我们想要增大这个歌值,则可通过写同一个文件来实现。

注意:对 proc 的写操作要注意权限问题,在修改时要小心,不适当的值可能会影响到系统的一运行。

Linux 中必须要了解的命令操作

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-24发表,共计6201字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中