APUE笔记-文件和目录

函数

lstat:不跟踪符号链接。

fstatat:路径可以是相对当前打开的目录,目录的文件描述符为fd,如果填写绝对路径,则fd被忽略。flag 设置为AT_SYMLINK_NOFOLLOW时不跟踪符号链接,默认跟踪符号链接。

#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstatat(int fd,const char *path, struct stat *buf,int flag);

struct stat结构体

st_mode成员可以用相关宏来测试:例如S_ISREG()测试是否是普通文件。

POSIX.1允许将IPC(进程间通信)对象说明为文件,信号量、消息队列、共享存储对象等。用宏来测试,例如S_TYPEISMQ()测试消息队列,传入的参数是指向stat结构体的指针。

struct stat {
    dev_t         st_dev;       //文件的设备编号
    ino_t         st_ino;       //节点
    mode_t        st_mode;      //文件的类型和存取的权限
    nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t         st_uid;       //用户ID
    gid_t         st_gid;       //组ID
    dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
    off_t         st_size;      //文件字节数(文件大小)
    unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
    unsigned long st_blocks;    //块数
    time_t        st_atime;     //最后一次访问时间
    time_t        st_mtime;     //最后一次修改时间
    time_t        st_ctime;     //最后一次改变时间(指属性)
};

实验:判断输入的文件类型

  1 #include <stdio.h>                                                                                                                                
  2 #include"apue.h"
  3 
  4 
  5 int main(int argc,char ** argv)
  6 {
  7     struct stat buf;
  8     if(argc!=2)
  9     {
 10         printf("error\n");
 11     }
 12     lstat(argv[1],&buf);
 13     if(S_ISREG(buf.st_mode))
 14         printf("regular");
 15     else if(S_ISDIR(buf.st_mode))
 16         printf("directory");
 17     else if (S_ISFIFO(buf.st_mode))
 18         printf("fifo");
 19     exit(0);
 20 }

关于ID

与进程相关的ID:

实际用户ID   实际组ID:标识我们究竟是谁

有效用户ID   有效组ID:决定我们的访问权限

保存的设置用户ID/组ID:在执行程序时包含了有效用户ID/组ID的副本。

可以在st_mode中设置标志,是的执行时此文件时,进程的有效用户ID/组ID是文件所有者的ID。例如passwd指令。

设置用户ID/组ID:在st_mode中,用S_ISUID   S_ISGID测试。

实验:目录的权限

建立一个目录hello,里面有个文件teat
将hello的权限改为000
cd hello/             bash: cd: hello/: 权限不够
chmod a+x hello       d--x--x--x 可以进入目录
ls                    ls: 无法打开目录'.': 权限不够(读权限允许获取文件列表,这里没有读权限)
chmod a+r hello       可以执行ls命令获取文件列表了
新建文件、删除文件需要对目录有写权限
关于删除:例如删除文件test,不需要对test有权限,只需要对test所在的目录有写权限。

实验:对文件的权限

新建文件test,写入0123456789,把文件权限改为000
vim test看到内容为空(没有读权限)
往文件写入123,给文件读权限,查看文件,发现写入成功
疑问:没给写权限,为什么写入成功了?

超级用户删除文件,不需要任何权限。即使改为000,也可以删除,读、写。也就是不受权限的限制。

测试文件权限

#include<unistd.h>

access和faccessat函数:按照实际的用户ID/组ID测试。

faccessat可以设置标志位(AT_EACCESS),测试有效用户ID/组ID。

进程有效用户ID为root,有所有权限。

进程用户ID,组ID等于文件相应的ID,则根据文件相应的权限

实验:测试输入文件的访问权限。

 1 #include <stdio.h>                                                                                                                                
  2 #include"apue.h"
  3 
  4 int main(int argc,char**argv)
  5 {
  6     if(argc!=2)
  7         printf("error\n");
  8     if(access(argv[1],R_OK)<0)
  9         printf("access error");
 10     else
 11         printf("read access OK\n");
 12     if(open(argv[1],O_RDONLY)<0)
 13         perror("open");
 14     else
 15         printf("open for reading OK\n");
 16     exit(0);
 17 }

函数umask

#include<sys/stat.h>

mode_t umask(mode_t cmask);返回之前的文件模式创建屏蔽字

cmask:由S_IRUSR S_IWUSR等按位或组成。

执行umask命令:0002,对应为为1,则关闭那一位的相关权限。

函数

chmod

fchmod

fchmodat

改变文件的权限。

粘着位

程序第一次执行,终止后,程序正文仍然在交换分区。

改变所有者的函数

chown   fchown    fchownat   lchown

和其他函数一样,有规律:at:表示可以相对路径定位文件,还带有flag标志位

f:表示文件描述度符

l:表示不跟踪符号链接

文件长度

stat结构体的st_size成员表示文件长度(单位:字节)

符号链接的文件长度是路径名的长度

ls -l报告的是文件长度,包括空洞的长度

du是文件的块数(Linux系统 设置了环境变量POSIXLY_CORECT,就是1024字节的块数,否则就是512),不包括空洞的长度

,空洞不占磁盘空间,但是复制文件会导致空洞被填满,填写为0.

文件截断

使用函数truncate ftruncate可以把文件截断为length(length大于原文件,可能会增加空洞)

打开文件时O_TRUNC可以把文件截断为0.

文件系统

extN能够通过inode一次性获得所有文件数据存放的位置(可以据此安排阅读顺序),fat32不可以。因此fat32会受到磁盘碎片的影响比较严重。extN也有磁盘碎片,影响不大。

df命令查看磁盘整体用量,读取superblock

sda是第一块硬盘 sdb是第二块硬盘

sda1是第一块串口硬盘的第一个分区

设备都在dev目录下,包括虚拟的和物理的

/dev/mapper/*是虚拟设备

tmpfs不对应任何设备,是真正的文件系统名称,这个文件系统是在内存中虚拟的。

目录包含目录项(文件名和inode编号)

创建链接的函数

创建新目录项和增加链接计数是原子操作。

不允许对于目录的硬链接。

关闭文件,首先检查打开文件的进程数,如果为0,检查链接计数,如果也是0,就删除文件内容。

创建临时文件的方法:open或者creat创建一个文件,然后立刻调用unlink,此时文件仍旧是打开的,不会被删除,进程结束或进程关闭文件时,文件被删除。

对于文件remove函数与unlink相同,对于目录remove与rmdir相同。

remove在stdio.h里面

文件或目录的重命名

#include<stdio.h>

rename

renameat

符号链接

硬链接直接指向inode,

目录的符号链接会导致循环(P98),由于unlink不跟随符号链接,所以可以处理。但是如果创建了构成这种循环的的硬链接,很难消除。

创建和读取符号链接

symlink

symlinkat

readlink

readlinkat

open跟随符号链接,因此可以readlink这类函数读取符号链接中的名字。

文件的时间

st_atim文件最后访问时间

st_ctim i节点状态最后修改时间

st_mtim文件最后修改时间

struct timeval {
time_t tv_sec; // seconds 
long tv_usec; // microseconds 
};

struct timespec {
time_t tv_sec; // seconds 
long tv_nsec; // and nanoseconds 
};

实验:

touch命令可以更新文件的三个时间。

1、touch hello
2、stat hello 
    最近访问:2018-08-30 15:36:11.451126384 +0800
    最近更改:2018-08-30 15:36:11.451126384 +0800
    最近改动:2018-08-30 15:36:11.451126384 +0800
3、cat hello后再查看
    最近访问:2018-08-30 15:37:17.408850806 +0800//这一个变了
    最近更改:2018-08-30 15:36:11.451126384 +0800
    最近改动:2018-08-30 15:36:11.451126384 +0800
4、vim hello 写入123
    最近访问:2018-08-30 15:38:47.015193507 +0800
    最近更改:2018-08-30 15:38:47.015193507 +0800
    最近改动:2018-08-30 15:38:47.071194971 +0800
5、chmod 777 hello
    最近访问:2018-08-30 15:38:47.015193507 +0800
    最近更改:2018-08-30 15:38:47.015193507 +0800
    最近改动:2018-08-30 15:40:05.269239409 +0800//这个变了,i节点有文件权限,改编权限,改变了i       节点


目录

#include<dirent.h>

创建目录  删除目录   读目录

rmdir函数可以删除空目录

打开目录返回DIR类型指针(DIR是一个内部结构类似于FILE)

struct dirent* readdir(DIR*dp)读取一次,第二次读取下一个目录项。

struct dirent   
{   
    long d_ino;//i节点编号
    off_t d_off;//在目录中的偏移
    unsigned short d_reclen;//文件名的长度
    unsigned char d_type;//文件类型
    char d_name [NAME_MAX+1];//文件名
}  
enum
{
DT_UNKNOWN = 0,
# define DT_UNKNOWN DT_UNKNOWN
DT_FIFO = 1,
# define DT_FIFO DT_FIFO
DT_CHR = 2,
# define DT_CHR DT_CHR
DT_DIR = 4,
# define DT_DIR DT_DIR
DT_BLK = 6,
# define DT_BLK DT_BLK
DT_REG = 8,
# define DT_REG DT_REG
DT_LNK = 10,
# define DT_LNK DT_LNK
DT_SOCK = 12,
# define DT_SOCK DT_SOCK
DT_WHT = 14
# define DT_WHT DT_WHT
};

实验:读取目录

  1 #include <stdio.h>
  2 #include "apue.h"                                                                                                                                 
  3 #include <dirent.h>
  4 
  5 int main(int argc,char** argv)
  6 {
  7     DIR* dir;
  8     struct dirent *sdir;
  9     if(argc!=2)
 10     {
 11         printf("error\n");
 12     }
 13     dir = opendir(argv[1]);
 14     if(dir==NULL)
 15         printf("opendir error\n");
 16     while((sdir=readdir(dir))!=NULL)
 17     {
 18         printf("%s\n",sdir->d_name);
 19     }
 20     printf("read end......\n");
 21 }

实验:文件遍历

注意:路径中/可以重复,例如cd  /home这样是可以的

  1 #include <stdio.h>                                                                                                                                
  2 #include "apue.h"
  3 #include <dirent.h>
  4 
  5 
  6 void scan_dir(char *path,int depth)
  7 {
  8     DIR* dir;
  9     struct dirent *sdir;
 10     if(path==NULL)
 11     {
 12         printf("path is empty\n");
 13         exit(-1);
 14     }
 15     dir = opendir(path);
 16     if(dir==NULL)
 17     {
 18         printf("opendir error\n");
 19         exit(-2);
 20     }
 21     while((sdir=readdir(dir))!=NULL)
 22     {
 23         if(sdir->d_type==DT_DIR)
 24         {
 25             if(strcmp(sdir->d_name,".")==0 || strcmp(sdir->d_name,"..")==0)
 26             {
 27                 int tmp_depth=depth;
 28                 while(tmp_depth)
 29                 {
 30                     tmp_depth--;
 31                     printf("  ");
 32                 }
 33 
 34                 printf("%s\n",sdir->d_name);
 35             }
 36             else
 37             {
 38                 int tmp_depth=depth;
 39                 while(tmp_depth)
 40                 {
 41                     tmp_depth--;
 42                     printf("  ");
 43                 }
 44                 printf("%s\n",sdir->d_name);
 45                 char str[255]={0};
 46                 sprintf(str,"%s/%s",path,sdir->d_name);
 47                 scan_dir(str,depth+1);
 48             }
 49         }
 50         else
 51         {
 52             int tmp_depth=depth;
 53             while(tmp_depth)
 54             {
 55                 tmp_depth--;
 56                 printf("  ");
 57             }
 58             printf("%s\n",sdir->d_name);
 59         }
 60     }
 61 
 62 }
 63 
 64 
 65 int main(int argc,char** argv)
 66 {
 67     if(argc!=2)
 68     {
 69         printf("error\n");
 70     }
 71     scan_dir(argv[1],0);
 72     printf("read end......\n");
 73 }        

运行结果

system.c
a.out
apue.h
..
dir.c
.
volatile.c
test
  hello
  ..
  .
  hello1
    hello
    ..
    .
getpgrp.c
read end......

改变当前工作目录的函数

chdir和fchdir

获取绝对路径

getcwd

  1 #include <stdio.h>                                                          
  2 #include "apue.h"
  3 
  4 
  5 int main()
  6 {
  7     char buf[255]={0};
  8     getcwd(buf,255);
  9     printf("%s\n",buf);
 10 }

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值