linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)

是操作系统提供的、与用户程序之间的接口,也就是操作系统提供给程序员的接口。从感觉上系统调用类似于过程调用,都由程序代码构成,使用方式相同,但两者有实质差别:过程调用只能在用户态下运行,不能进入核心态;而系统调用可以实现从用户态到核心态的转变。

linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)(1)

Linux文件描述符

文件描述符fd是进程打开文件列表中的序号,它是一个0~255的整数。文件描述符0、1、2分别用于表示标准输入、标准输出和标准错误文件。进程打开一个文件后,就一直使用文件描述符fd来对文件进行标识并进行各种操作,它是文件正在被进程使用的标志。

linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)(2)

open系统调用

调用open可以打开或创建一个文件。

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int oflag, ... /* mode_t mode */);

返回:若成功为文件描述符,若出错为- 1

我们将第三个参数写为. . .,这是ANSI C说明余下参数的数目和类型可以变化的方法。对于open函数而言,仅当创建新文件时才使用第三个参数。在函数原型中此参数放置在注释中。

第一个参数**pathname*是要打开或创建的文件的名字。

第二个参数oflag参数可用来说明此函数的多个选择项。用下列一个或多个常数进行或运算构成oflag*参数(这些常数定义在< fcntl . h >头文件中, 在这三个常数中应当只指定一个):

  • O_RDONLY 只读打开
  • O_WRONLY 只写打开
  • O_RDWR 读、写打开

第三个可选参数:

  • O_APPEND 每次写时都加到文件的尾端。
  • O_CREAT 若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。
  • O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则出错。这可测试一个文件是否存在。
  • O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。
  • O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。
  • O_SYNC 使每次write都等到物理I / O操作完成。

由open函数返回的文件描述符一定是最小的未用描述符数字。

举例:

int fd; //定义一个整型的文件描述符 char path[]=“/proc/version” //记录Linux内核版本的文件 fd=open(path,O_RDONLY) //以只读方式打开

更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)(3)

linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)(4)

Linux鍐呮牳婧愮爜/鍐呭瓨璋冧紭/鏂囦欢绯荤粺/杩涚▼绠$悊/璁惧椹卞姩/缃戠粶鍗忚鏍�-瀛︿範瑙嗛鏁欑▼-鑵捐璇惧爞

close调用

可用close关闭一个打开文件:

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

返回:若成功为0,若出错为-1

关闭一个文件时也释放该进程加在该文件上的所有记录锁。当一个进程终止时,它所有的打开文件都由内核自动关闭。

lSEEK调用

每个打开的文件都有一个与其相关联的“当前文件位移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。

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

返回:若成功为新的文件位移,若出错为-1

对参数offset 的解释与参数whence的值有关

  • 若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset 个字节
  • 若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset, offset可为正或负
  • 若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset, offset可为正或负

若lseek成功执行,则返回新的文件位移量,为此可以用下列方式确定一个打开文件的当前位移量:

off_t currpos; currpos = lseek(fd, 0, SEEK_CUR);

这种方法也可用来确定所涉及的文件是否可以设置位移量。如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE。

lseek仅将当前的文件位移量记录在内核内,它并不引起任何I / O操作。然后,该位移量用于下一个读或写操作。

文件位移量可以大于文件的当前长度,这种情况下,对该文件的下一次写将延长该文件并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被读为0。

read调用

用read从打开的文件中读数据。

#include <unistd.h> ssize_t read(int fd, void *buff, size_t nbytes) ;

返回:读到的字节数,若已到文件尾为0,若出错为-1

write调用

用write函数向打开文件写数据。

#include <unistd.h> ssize_t write(int fd, const void *buf, size_t nbytes) ;

返回:若成功为已写的字节数,若出错为-1

其返回值通常与参数nbytes的值不同,否则表示出错。write出错的一个常见原因是:磁盘已写满,或者超过了对一个给定进程的文件长度限制。

对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

unlink调用

unlink()函数功能即为删除文件。执行unlink()函数会删除所给参数指定的文件。

#include<unistd.h> int unlink(const char *pathname); // pathname:指定要移除的链接文件。

成功返回0;失败则返回-1,同时设置errno为相应值。

执行unlink()函数并不一定会真正的删除文件,它先会检查文件系统中此文件的连接数是否为1,如果不是1说明此文件还有其他链接对象,因此只对此文件的连接数进行减1操作。若连接数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉。在有进程打开此文件的情况下,则暂时不会删除,直到所有打开该文件的进程都结束时文件就会被删除。

文件锁

fcntl函数可以改变已经打开文件的性质。

#include <sys/types.h> #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd,.../* int arg * / );

返回:若成功则依赖于cmd(见下),若出错为-1

  • fcntl函数有5种功能:
  • 复制一个现有的描述符(cmd=F_DUPFD).
  • 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
  • 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
  • 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
  • 获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).

当多个用户共同使用、操作一个文件也即文件共享的情况下,Linux通常采用给文件上锁的方法来避免产生竞争。

文件锁的数据结构:

struct flock{ short l_type; // 锁类型,可取值为F_RDLCK、F_WRLCK、F_UNLCK off_t l_start; // 相对偏移量 short l_whence; // 位移量起点:SEEK_SET文件开头、SEEK_CUR文件指针当前位置、SEEK_END文件尾 off_t l_len; // 加锁区域长度 pid_t l_pid; // 加锁进程的进程号 }

拓展

/proc 文件系统是一种内核和内核模块用来向进程 (process) 发送信息的机制。这个伪文件系统让你可以和内核内部数据结构进行交互,获取有关进程的有用信息,在运行中改变设置。与其他文件系统不同,/proc 存在于内存之中而不是硬盘上。proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息。

下面是一些重要的文件:

  • /proc/cpuinfo - CPU 的信息 (型号, 家族, 缓存大小等)
  • /proc/meminfo - 物理内存、交换空间等的信息
  • /proc/mounts - 已加载的文件系统的列表
  • /proc/devices - 可用设备的列表
  • /proc/filesystems - 被支持的文件系统
  • /proc/modules - 已加载的模块
  • /proc/version - 内核版本
  • /proc/cmdline - 系统启动时输入的内核命令行参数

有一些以数字命名的目录,它们是进程目录。系统中当前运行的每一个进程在/proc下都对应一个以进程号为目录名的目录/proc/pid,它们是读取进程信息的接口。

通过 /proc 中可读写的文件提供了对内核的交互机制。写这些文件可以改变内核的状态。大部分 /proc 的文件是只读的,/proc/sys 目录存放所有可读写的文件的目录,可以被用于改变内核行为, /proc/sys/kernel目录包含反通用内核行为的信息。

实验

编写两个源代码文件read_lock.c和write_lock.c,分别调用lock_set函数对文件加读锁和写锁。

// lock.c 实现加锁 #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> int lock_set(int fd,int type) { struct flock old_lock,lock; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; lock.l_type = type; lock.l_pid = -1; fcntl(fd,F_GETLK,&lock); if(lock.l_type != F_UNLCK) { if(lock.l_type == F_RDLCK) printf("Read lock already set by %d\n",lock.l_pid); else if(lock.l_type == F_WRLCK) printf("Write lock already set by %d\n",lock.l_pid); } lock.l_type = type; if((fcntl(fd,F_SETLKW,&lock)) < 0) { printf("Lock failed:type = %d\n",lock.l_type); return 1; } switch(lock.l_type) { case F_RDLCK: printf("Read lock set by %d\n",getpid()); break; case F_WRLCK: printf("Write lock set by %d\n",getpid()); break; case F_UNLCK: printf("Release lock set by %d\n",getpid()); return 1; break; default: break; } return 0; }// 读锁 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include "lock.c" int main(){ char filepath[] = "./test"; int fd = open(filepath, O_RDONLY); lock_set(fd, F_RDLCK); getchar(); return 0; }// 写锁 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include "lock.c" int main(){ char filepath[] = "./test"; int fd = open(filepath, O_WRONLY); lock_set(fd, F_WRLCK); getchar(); return 0; }

原文地址:linux-鏂囦欢绯荤粺璋冪敤-鍩轰簬C璇█ - 澶滈〉瀛� - 鍗氬鍥�

linux中c语言读取配置文件(一文讲解linux-文件系统调用-基于C语言)(5)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页