linux多个进程写同一个文件路径,Linux C 系统编程(03) 文件与I/O 文件目录

该系列文章总纲链接:专题分纲目录 LinuxC 系统编程​​​​​​​

本章节思维导图如下所示(思维导图会持续迭代):

第一层:

2182e88084e8bb7981a07be0fd1678a3.png

第二层:

3afe85b7a6225dfcf8bbfdf1190c00d2.png

目录操作:目录文件本质上是一个文件,但是实际上其内容又与普通文件不同。目录文件是一种特殊的文件,其内容存储着目录下所有文件的目录项。用户可以像普通文件一样读写目录,不过需要使用一组特殊的系统调用。

1 目录权限

目录文件的访问权限和普通文件是一样的,对于目录权限而言有:

S_IRUSR     :0400:用户-读

S_IWUSR     :0200:用户-写

S_IXUSR     :0100:用户-执行

S_IRGRP     :0040:用户组-读

S_IWGRP     :0020:用户组-写

S_IXGRP     :0010:用户组-执行

S_IROTH     :0004:其他用户-读

S_IWOTH     :0002:其他用户-写

S_IXOTH     :0001:其他用户-执行

其中读、写、可执行分别表示:

读          :表示可以列出该目录所有的文件

写          :表示可以创建文件、删除文件

可执行  :表示可以打开目录,路径有效,一般都要有这个权限

测试目录文件:S_ISDIR(stat结构体变量.st_mode);为0,表示是目录文件;为非0,表示非目录文件。

设置用户ID位对目录没有意义,但是设置用户组ID对目录却有很大的意义。因为如果设置用户组ID被设置,则在该目录下创建的任何目录和文件的组ID都将设置为该目录的组ID。

2 目录操作

2.1 创建一个目录 mkdir

linux下使用mkdir函数来创建一个目录。mkdir函数的接口:

#include #include int mkdir(const char *pathname, mode_t mode);

参数pathname     :要创建的目录的路径。

参数mode          :目录的操作权限(一般情况下,一定要加上可执行的权限)。

函数成功执行返回0,失败返回-1。

注意:

一个目录总要包含两个默认的目录项,即.(当前目录)和..(上一级目录)。

在linux下,新创建的子目录会自动继承父目录的设置组ID位,而不是创建进程的组ID。

2.2 删除一个目录 rmdir

linux下使用rmdir函数来创建一个目录。rmdir函数的接口:

#include int rmdir(const char *pathname);

参数pathname     :要删除的目录的路径。

函数成功执行返回0,失败返回-1。

注意:

rmdir函数只能删除一个空目录,如果目录非空,则删除出错。(这里的空目录表示目录项只含有.和..文件)

如果目录的权限中没有写的权限,那么删除目录也会发生错误。

2.3 目录项结构 struct dirent

用户不可以直接对目录进行写的操作,这个操作完全是由内核来完成的,因此linux下不提供写目录的函数接口。一个目录文件中存着目录中所有文件的目录项,对目录的读写实际上就是操作这些目录项。目录项使用dirent结构表示,该结构体定义在dirent.h文件中:

struct dirent

{

#ifndef __USE_FILE_OFFSET64           /*用于64位的文件系统*/

__ino_t          d_ino;          /* inode number 索引节点号 */

off_t                d_off;     /*在目录文件中的偏移 */

#else

__ino64_t     d_ino;             /* inode number 索引节点号 */

off_64t           d_off;        /*在目录文件中的偏移 */

#endif

unsigned short int d_reclen;    /*文件名长 */

unsigned char d_type;           /*文件类型 */

char d_name [NAME_MAX+1]; /*文件名,最长255字符 */

};

2.4 打开与关闭目录 opendir closedir

linux下使用opendir函数来创建一个目录。opendir函数的接口:

#include #include DIR *opendir(const char *name);

参数name     :要打开的目录的路径。

open返回的是一个DIR结构的指针,该结构类似于FILE指针,只不过用来保存所打开目录的信息。

linux下使用closedir函数来创建一个目录。closedir函数的接口:

#include #include int closedir(DIR *dirp);

参数dirp:要关闭的目录的DIR结构指针。

函数成功执行返回0,失败返回-1。

opendir和closedir是配套使用的,如果只打开目录而没有关闭,那么该进程就会因为打开的文件数过多而不能打开任何文件。这里的DIR结构体定义如下:

struct __dirstream

{

void *__fd;           /* `struct hurd_fd' pointer for descriptor. */

char *__data;      /* Directory block. */

int __entry_data;  /* Entry number `__data' corresponds to. */

char *__ptr;           /* Current pointer into the block. */

int __entry_ptr;      /* Entry number `__ptr' corresponds to. */

size_t __allocation;      /* Space allocated for the block. */

size_t __size;           /* Total valid data in the block. */

__libc_lock_define (, __lock)      /* Mutex lock for this structure. */

};

typedef struct __dirstream DIR;

2.5 读目录

在进行读目录项操作的时候,会改变目录文件的当前读写位置。linux下使用readdir函数来读取目录中的内容。

readdir函数的原型:

#include struct dirent *readdir(DIR *dirp);

参数dirp:要读取的目录的DIR结构指针。

函数返回一个dirent类型的指针,指针中存放着每个文件的目录项,如果目录到达结尾或者发生错误,readdir函数返回NULL。

如果要判断readdir是因为目录到达结尾还是发生错误,需要通过errno变量来判断。

2.6 得到目录文件的读写位置

对目录的读写操作会影响到目录文件的当前位置,同样,目录文件也可以像普通文件一样被定位。linux下使用telldir函数得到当前目录文件的读写位置。telldir函数的原型:

#include long telldir(DIR *dirp);

参数dirp:需要得到读写位置的目录的DIR结构指针。

函数执行成功返回目录文件当前的读写位置,失败返回-1。

2.7 定位目录

目录文件可以随意更改文件当前的读写位置,在linux下使用seekdir函数来实现文件定位的功能。seekdir函数的原型:

#include void seekdir(DIR *dirp, long offset);

参数dirp     :需要定位的目录的DIR结构指针。

参数offset     :要定位的偏移值。(如果该值超过了有效的目标文件的范围,seekdir函数将会出错)

函数无返回值。

注意: 打开一个目录文件,一个目录项占用12个字节,向后偏移24个字节就可以跳过.文件和..文件两个目录项。

2.8 回卷目录文件

若想重新读取文件目录中的内容又想部关闭目录文件,可以使用回卷函数rewinddir,使得目录文件的读写位置回到文件的起始处。rewinddir函数的原型:

#include #include void rewinddir(DIR *dirp);

参数dirp:需要回卷的目录的DIR结构指针。

函数无返回值。

3 进程的工作目录

每个进程都有一个工作目录,如果程序使用了相对路径,进程以当前目录为起点搜索相对路径。shell解释器解释的每一个命令实际上都是一个程序,这些程序大部分存储在/bin文件夹下,但是里面没有cd这个程序,也就是说,cd的实现方法和其他命令不同其他的命令可以独立于shell而存在,但是cd命令不可以。

注意:因为shell会调用fork函数创建一个子进程来执行命令,如果在子进程中调用chdir函数改变工作目录不会影响到父进程shell。

3.1 改变工程的工作目录

linux下使用chdir函数实现改变进程的工作目录。chdir函数的原型:

#include int chdir(const char *path);

int fchdir(int fd);

参数path:打算改变的新工作目录的路径名。

参数fd:新路径名的文件描述符

函数执行成功返回0,失败返回-1。

程序执行后相当于cd命令,但是只对本身进程以及自己创建的子进程有效,对父进程无效。

fchdir 用来将当前目录改为参数fd(文件描述符)指定的目录。

3.2 得到进程的当前工作目录

使用pwd可以查看当前的工作目录,在linux下使用getcwd函数获取当前进程的工作目录。getcwd函数的原型:

#include char *getcwd(char *buf, size_t size);

参数buf     :存储当前路径名的缓冲区,属于值结果参数。

参数size:缓冲区的大小(路径名+‘\0’的长度),一般不要定义太小。

函数执行成功则返回缓冲区的地址,失败返回NULL。

3.3 子进程工作目录对父进程的影响

子进程中改变工作目录不会对父进程造成影响,但是会对自己的子进程造成影响,自己的子进程会继承父进程的工作目录。对于cd命令,它是直接实现在shell中的,因此如果在本身的进程中想要改变工作目录不要使用system(“cd”)命令。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值