0%

unix环境高级编程 - 文件目录

最近在学习 APUE,所以顺便将每日所学记录下来,一方面为了巩固学习的知识,另一方面也为同样在学习APUE的童鞋们提供一份参考。

本系列博文均根据学习《UNIX环境高级编程》一书总结而来;

运行环境:

  • 操作系统: ubutnu 16.04
  • 编译器:QtCreator CLion 2020.3

文件属性

stat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);


struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */ //文件权限
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */ //用户ID
gid_t st_gid; /* group ID of owner */ //组ID
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */ //最后一次修改时间
time_t st_ctime; /* time of last status change */
};

st_mode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
目前,st_mode使用了其低19bit. 0170000 => 1+ 3*5 = 16.
其中,最低的9位(0-8)是权限,9-11是id,12-15是类型。
具体定义如下:
S_IFMT 0170000 bitmask for the file type bitfields
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 fifo
S_ISUID 0004000 set UID bit
S_ISGID 0002000 set GID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permisson
S_IXOTH 00001 others have execute permission



//使用宏快速判断文件类型
S_ISREG(m) is it a regular file?

S_ISDIR(m) directory?

S_ISCHR(m) character device?

S_ISBLK(m) block device?

S_ISFIFO(m) FIFO (named pipe)?

S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)

S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


int main(int argc,char* args[])
{
//int stat(const char *path, struct stat *buf);
struct stat st;
stat(args[1],&st);
/*
//获取文件类型
if((st.st_mode & S_IFMT) == S_IFREG)
{
printf("普通文件\n");
}
else if((st.st_mode & S_IFMT) == S_ISDIR)
{
printf("目录文件\n");
}
else if((st.st_mode & S_IFMT) == S_ISLNK)
{
printf("链接文件\n");
}
*/


switch (st.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}

return 0;
}

lstat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//lstat函数详解
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


int main(int argc,char* args[])
{
//int lstat(const char *path, struct stat *buf);
int fd = open(args[1],O_RDONLY);
struct stat st;
int n = lstat(args[1],&st);
if(n<0)
{
perror("open file");
return -1;
}
printf("%d %d %d \n",st.st_uid,st.st_gid,st.st_size);
}

stat 函数与 lstat 函数的区别: 当一个文件是符号链接时,lstat 函数返回的是该符号链接本身的信息;而 stat 函数返回的是该链接指向文件的信息。

目录

opendir

打开一个目录,打开成功返回指向目录的指针;

1
DIR *opendir(const char *name);

closedir

关闭目录

1
int closedir(DIR *dirp);

成功返回0,错误返回-1

readdir

读取目录内容–目录项

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
int readdir(unsigned int fd, struct old_linux_dirent *dirp,unsigned int count);

struct old_linux_dirent {
long d_ino; /* inode number */
off_t d_off; /* offset to this old_linux_dirent */
unsigned short d_reclen; /* length of this d_name */
char d_name[NAME_MAX+1]; /* filename (null-terminated) */
}


demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
int main(int argc,char* args[])
{
//DIR *opendir(const char *name);
DIR *pDir = opendir(args[1]);
if(pDir==NULL)
{
perror("opendir error");
return -1;
}

//struct dirent *readdir(DIR *dirp);

//int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

struct dirent *pDent = NULL;
while((pDent=readdir(pDir))!=NULL)
{
if(strcmp(pDent->d_name,".")==0 || strcmp(pDent->d_name,"..")==0) //去除.文件
{
continue;
}
printf("%s->",pDent->d_name);
switch(pDent->d_type)
{
case DT_REG:
printf("普通文件\n");
break;
case DT_DIR:
printf("目录文件\n");
break;
case DT_LNK:
printf("链接文件\n");
break;
}
}

return 0;
}

access

1
2
3
#include <unistd.h>

int access(const char *pathname, int mode);

access修改文件权限;

truncate

文件截断

dup

复制一个文件描述符

1
int dup(int oldfd);

oldfd -要复制的文件描述符;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc,char* args[])
{
int fd = open(args[1],O_RDWR); //旧文件描述符
if(fd<0)
{
perror("open error");
return -1;
}
int newfd = dup(fd); //新文件描述符
printf("fd = %d newfd = %d\n",fd,newfd);

char buf[1024];
memset(buf,0,sizeof(buf));
write(fd,"hello,world\n",sizeof("hello,world\n")); //使用旧的文件描述符写入文件
//SEEK_SET
lseek(fd,0,SEEK_SET); //移动文件指针到最开始
int n = read(newfd,buf,sizeof(buf)); //使用新的文件描述符读
printf("read over:%d %s\n",n,buf);
close(fd);
close(newfd);
return 0;
}

dup2

如果调用dup2的时候,旧的文件描述符如果打开了一个文件,那么先关闭旧的文件描述符,然后指向新的文件描述符,如果旧的未指向,则全部指向新的文件描述符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc,char* args[])
{
int fd = open(args[1],O_RDWR);
int fd1 = open(args[2],O_RDWR);
if(fd<0)
{
perror("open error");
return -1;
}


if(fd1<0)
{
perror("open error");
return -1;
}
dup2(fd,fd1);
printf("fd = %d fd1 = %d\n",fd,fd1);

char buf[1024];
memset(buf,0,sizeof(buf));
write(fd,"hello,world\n",sizeof("hello,world\n"));
//SEEK_SET
lseek(fd1,0,SEEK_SET);
int n = read(fd1,buf,sizeof(buf));
printf("read over:%d %s\n",n,buf);
close(fd);
close(fd1);
return 0;
}