uc笔记06---chmod/fchmod,chown/fchown/lchown
2015-09-30 16:58
393 查看
1. chmod/fchmod 修改文件的权限
#include <sys/stat.h>
int chmod (
const char* path, // 文件路径
mode_t mode // 文件权限
);
int fchmod (
int fd, // 文件路径
mode_t mode // 文件权限
);
成功返回 0,失败返回 -1。
mode 为以下值的位或(直接写八进制整数形式亦可,
如 07654 - rwSr-sr-T):
S U G D
7 6 5 4
4 2 1 4 2 0 4 0 1 4 0 0
ugt rw- r-x r-- -> rwSr-sr-T
S_ISUID - 设置用户ID
S_ISGID - 设置组ID
S_ISVTX - 粘滞
------------------------------
S_IRUSR(S_IREAD) - 属主可读
S_IWUSR(S_IWRITE) - 属主可写
S_IXUSR(S_IEXEC) - 属主可执行
------------------------------
S_IRGRP - 属组可读
S_IWGRP - 属组可写
S_IXGRP - 属组可执行
------------------------------
S_IROTH - 其它可读
S_IWOTH - 其它可写
S_IXOTH - 其它可执行
范例:chmod.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main (void) {
int fd = open ("chmod.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror ("open");
return -1;
}
// if (fchmod (fd, 07654) == -1) {
if (fchmod (fd,
S_ISUID | S_ISGID | S_ISVTX |
S_IRUSR | S_IWUSR |
S_IRGRP | S_IXGRP |
S_IROTH) == -1) {
perror ("fchmod");
return -1;
}
close (fd);
return 0;
}
2. chown/fchown/lchown 修改文件的属主和属组
通过命令方式修改属主和属组:
# chown <uid>:<gid> <file>
通过函数方式修改属主和属组:
#include <unistd.h>
int chown (
const char* path, // 文件路径
uid_t owner, // 属主ID
gid_t group // 属组ID
);
int fchown (
int fildes, // 文件描述符
uid_t owner, // 属主ID
gid_t group // 属组ID
);
int lchown (
const char* path, // 文件路径(不跟踪软链接)
uid_t owner, // 属主ID
gid_t group // 属组ID
);
成功返回 0,失败返回 -1。
注意:
1. 属主和属组 ID 取 -1 表示不修改。
2. 超级用户进程可以修改文件的属主和属组,
普通进程必须拥有该文件才可以修改其属主和属组。
3. truncate/ftruncate 修改文件的长度,截短丢弃,加长添零。
#include <unistd.h>
int truncate (
const char* path, // 文件路径
off_t length // 文件长度
);
int ftruncate (
int fd, // 文件描述符
off_t length // 文件长度
);
成功返回 0,失败返回 -1。
范例:trunc.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
int main (void) {
const char* text = "Hello, World !";
size_t size = (strlen (text) + 1) * sizeof (text[0]); // +1 给 \0 用
int fd = open ("trunc.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror ("open");
return -1;
}
if (ftruncate (fd, size) == -1) {
perror ("ftruncate");
return -1;
}
// 把文件和内存建立映射
void* map = mmap (NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED/*MAP_PRIVATE*/, fd, 0);
if (map == MAP_FAILED) {
perror ("mmap");
return -1;
}
// 往内存里写
memcpy (map, text, size);
printf ("%s\n", map);
// 解映射
munmap (map, size);
close (fd);
return 0;
}
运行测试:
#gcc trunc.c
#hexdump -C trunc.txt // 十六进制查看
#./a.out
Hello, World !
在 trunc.txt 建立好的基础上,我们写下面的测试程序,实现两个程序之间共享数据:
范例:mmap.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main (void) {
int fd = open ("trunc.txt", O_RDONLY);
if (fd == -1) {
perror ("open");
return -1;
}
struct stat st; // 用于下面求文件大小
if (fstat (fd, &st) == -1) {
perror ("fstat");
return -1;
}
// 两个内存映射到同一个文件
void* map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
perror ("mmap");
return -1;
}
printf ("%s\n", map);
munmap (map, st.st_size);
close (fd);
return 0;
}
运行测试:
#gcc mmap.c
#hexdump -C trunc.txt // 十六进制查看
#./a.out
Hello, World !
注意:对于文件映射,
私有映射 (MAP_PRIVATE) 将数据写到缓冲区而非文件中,只有自己可以访问。
而对于内存映射,
私有 (MAP_PRIVATE) 和公有 (MAP_SHARED) 没有区别,都是仅自己可以访问。
4. link/unlink/remove/rename
link: 创建文件的硬链接(目录条目)。
unlink: 删除文件的硬链接(目录条目)。
只有当文件的硬链接数降为 0 时,文件才会真正被删除。
若该文件正在被某个进程打开,其内容直到该文件被关闭才会被真正删除。
remove: 对文件同 unlink,对目录同 rmdir (不能删非空目录)。
rename: 修改文件/目录名。
#include <unistd.h>
int link (
const char* path1, // 文件路径
const char* path2 // 链接路径(硬链接)
);
int unlink (
const char* path // 链接路径
);
#include <stdio.h>
int remove (
const char* pathname // 文件/目录路径
);
int rename (
const char* old, // 原路径名
const char* new // 新路径名
);
成功返回 0,失败返回 -1。
5. symlink/readlink
symlink: 创建软链接;目标文件可以不存在,也可以位于另一个文件系统中。
里面存放着目标文件的名称;
readlink: 获取软链接文件本身(而非其目标)的内容。
open: 不能打开软链接文件本身,打开的是软链接目标。
#include <unistd.h>
int symlink (
const char* oldpath, // 文件路径(可以不存在)
const char* newpath // 链接路径(软链接)
);
成功返回 0,失败返回 -1。
ssize_t readlink (
const char* restrict path, // 软链接文件路径
char* restrict buf, // 缓冲区(存放目标文件路径)
size_t bufsize // 缓冲区大小
);
成功返回实际拷入缓冲区 buf 中软链接文件内容的字节数,失败返回 -1。
范例:slink.c
#include <stdio.h>
#include <limits.h>
int main (int argc, char* argv[]) {
if (argc < 3) {
fprintf (stderr, "用法:%s <文件> <软链接>\n", argv[0]);
return -1;
}
// 建立软链接
if (symlink (argv[1], argv[2]) == -1) {
perror ("symlink");
return -1;
}
char slink[PATH_MAX+1] = {0}; // 目标文件路径
if (readlink (argv[2], slink,
sizeof (slink) - sizeof (slink[0])) == -1) { // - sizeof (slink[0] 用于留一位给 \0
perror ("readlink");
return -1;
}
printf ("%s是%s的软链接。\n", argv[2], slink);
return 0;
}
运行测试:
#./a.out
#./a.out none.txt slink.txt
slink.txt 是 none.txt 的软链接。
slink.txt 大小为 8 字节,刚好是 none.txt 的名字大小;
而 none.txt 大小为 20 字节,里面存放的是真正的内容,所以较大;
6. mkdir/rmdir 创建/删除空目录
#include <sys/stat.h>
int mkdir (
const char* path, // 目录路径
mode_t mode // 访问权限,目录的执行权限(x)表示可进入
);
#include <unistd.h>
int rmdir (
const char* path // 目录路径
);
成功返回 0,失败返回 -1。
7. chdir/fchdir/getcwd
chdir/fchdir: 更改当前工作目录。
工作目录是进程的属性,只影响调用进程本身。
getcwd: 获取当前工作目录(绝对路径)。
#include <unistd.h>
int chdir (
const char* path // 工作目录路径
);
int fchdir (
int fildes // 工作目录描述符(由 open 函数返回)
);
成功返回 0,失败返回 -1。
char* getcwd (
char* buf, // 缓冲区
size_t size // 缓冲区大小
);
成功返回当前工作目录字符串指针,失败返回 NULL。
范例:dir.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
int main (void) {
char cwd[PATH_MAX+1]; // 用于装载当前目录
if (! getcwd (cwd, sizeof (cwd))) {
perror ("getcwd");
return -1;
}
printf ("当前工作目录:%s\n", cwd);
// 创建目录
if (mkdir ("work", 0755) == -1) {
perror ("mkdir");
return -1;
}
// 相当于 cd,进入目录
if (chdir ("work") == -1) {
perror ("chdir");
return -1;
}
if (! getcwd (cwd, sizeof (cwd))) {
perror ("getcwd");
return -1;
}
printf ("当前工作目录:%s\n", cwd);
if (mkdir ("empty", 0755) == -1) {
perror ("mkdir");
return -1;
}
if (rmdir ("empty") == -1) {
perror ("rmdir");
return -1;
}
// 如果没有删除 empty,下面这段代码就会报错,因为 work 目录非空;
if (rmdir ("../work") == -1) {
perror ("rmdir");
return -1;
}
return 0;
}
8. opendir/fdopendir/closedir/readdir/rewinddir/telldir/seekdir
opendir/fdopendir: 打开目录流。
closedir: 关闭目录流。
readdir: 读取目录流。
rewinddir: 复位目录流。
telldir: 获取目录流当前位置。
seekdir: 设置目录流当前位置。
#include <sys/types.h>
#include <dirent.h>
DIR* opendir (
const char* name // 目录路径
);
DIR* fdopendir (
int fd // 目录描述符(由open函数返回)
);
成功返回目录流指针,失败返回 NULL。
int closedir (
DIR* dirp // 目录流指针
);
成功返回 0,失败返回 -1。
struct dirent* readdir (
DIR* dirp // 目录流指针
);
成功返回下一个目录条目结构体的指针,
到达目录尾(不置 errno)或失败(设置 errno)返回 NULL。
struct dirent {
ino_t d_ino; // i节点号
off_t d_off; // 下一个条目的偏移量
// 注意是磁盘偏移量,而非内存地址偏移
unsigned short d_reclen; // 记录长度
unsigned char d_type; // 文件类型
char d_name[256]; // 文件名
};
d_type取值:
DT_DIR - 目录
DT_REG - 普通文件
DT_LNK - 软链接
DT_BLK - 块设备
DT_CHR - 字符设备
DT_SOCK - Unix域套接字
DT_FIFO - 有名管道
DT_UNKNOWN - 未知
范例:list.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
DIR* dp = opendir (argv[1]);
if (! dp) {
perror ("opendir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp)) {
switch (de -> d_type) {
case DT_DIR:
printf (" 目录:");
break;
case DT_REG:
printf (" 普通文件:");
break;
case DT_LNK:
printf (" 软链接:");
break;
case DT_BLK:
printf (" 块设备:");
break;
case DT_CHR:
printf (" 字符设备:");
break;
case DT_SOCK:
printf ("Unix域套接字:");
break;
case DT_FIFO:
printf (" 有名管道:");
break;
default:
printf (" 未知:");
break;
}
printf ("%s\n", de -> d_name);
}
if (errno) {
perror ("readdir");
return -1;
}
closedir (dp);
return 0;
}
练习:打印给定路径下的目录树
代码:tree.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
/*
#include <limits.h>
*/
int tree (const char* dir, size_t depth) {
DIR* dp = opendir (dir);
if (! dp) {
perror ("opendir");
return -1;
}
if (chdir (dir) == -1) { // 进入目录
perror ("chdir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp))
if (de -> d_type != DT_DIR)
printf ("%*s%s\n", depth * 2, "", de -> d_name); // 缩进
else if (strcmp (de -> d_name, ".") && // 不能进入本目录和父目录
strcmp (de -> d_name, "..")) {
printf ("%*s%s/\n", depth * 2, "", de -> d_name);
/*
char subdir[PATH_MAX+1];
sprintf (subdir, "%s/%s", dir, de -> d_name);
if (tree (subdir, depth + 1) == -1)
return -1;
*/
if (tree (de -> d_name, depth + 1) == -1)
return -1;
}
if (errno) { // errno 非零则表示出错
perror ("readdir");
return -1;
}
if (chdir ("..") == -1) {
perror ("chdir");
return -1;
}
closedir (dp);
return 0;
}
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
return tree (argv[1], 0);
}
回到头位置:
void rewinddir (
DIR* dirp // 目录流指针
);
得到当前位置:
long telldir (
DIR* dirp // 目录流指针
);
成功返回目录流的当前位置,失败返回 -1。
设置起始位置:
void seekdir (
DIR* dirp, // 目录流指针
long offset // 位置偏移量
);
+---------------------+ +-----------------------+
| v | v
+-------+----|---+-----+-------+ +-------+----|---+-----+--------+ +-------
| d_ino | d_off | ... | a.txt | ... | d_ino | d_off | ... | b.txt | ... | d_ino
+-------+-------+-----+-------+ +-------+--------+-----+-------+ +-------
^ ^
| -- readdir() -> |
范例:seek.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
DIR* dp = opendir (argv[1]);
if (! dp) {
perror ("opendir");
return -1;
}
seekdir (dp, 1722002057); // 设置起始位置
rewinddir (dp); // 回到头位置
long offset = telldir (dp);
if (offset == -1) {
perror ("telldir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp)) {
printf ("[%010d %010d] ", offset, de -> d_off);
switch (de -> d_type) {
case DT_DIR:
printf (" 目录:");
break;
case DT_REG:
printf (" 普通文件:");
break;
case DT_LNK:
printf (" 软链接:");
break;
case DT_BLK:
printf (" 块设备:");
break;
case DT_CHR:
printf (" 字符设备:");
break;
case DT_SOCK:
printf ("Unix域套接字:");
break;
case DT_FIFO:
printf (" 有名管道:");
break;
default:
printf (" 未知:");
break;
}
printf ("%s\n", de -> d_name);
if ((offset = telldir (dp)) == -1) {
perror ("telldir");
return -1;
}
}
if (errno) {
perror ("readdir");
return -1;
}
closedir (dp);
return 0;
}
#include <sys/stat.h>
int chmod (
const char* path, // 文件路径
mode_t mode // 文件权限
);
int fchmod (
int fd, // 文件路径
mode_t mode // 文件权限
);
成功返回 0,失败返回 -1。
mode 为以下值的位或(直接写八进制整数形式亦可,
如 07654 - rwSr-sr-T):
S U G D
7 6 5 4
4 2 1 4 2 0 4 0 1 4 0 0
ugt rw- r-x r-- -> rwSr-sr-T
S_ISUID - 设置用户ID
S_ISGID - 设置组ID
S_ISVTX - 粘滞
------------------------------
S_IRUSR(S_IREAD) - 属主可读
S_IWUSR(S_IWRITE) - 属主可写
S_IXUSR(S_IEXEC) - 属主可执行
------------------------------
S_IRGRP - 属组可读
S_IWGRP - 属组可写
S_IXGRP - 属组可执行
------------------------------
S_IROTH - 其它可读
S_IWOTH - 其它可写
S_IXOTH - 其它可执行
范例:chmod.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main (void) {
int fd = open ("chmod.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror ("open");
return -1;
}
// if (fchmod (fd, 07654) == -1) {
if (fchmod (fd,
S_ISUID | S_ISGID | S_ISVTX |
S_IRUSR | S_IWUSR |
S_IRGRP | S_IXGRP |
S_IROTH) == -1) {
perror ("fchmod");
return -1;
}
close (fd);
return 0;
}
2. chown/fchown/lchown 修改文件的属主和属组
通过命令方式修改属主和属组:
# chown <uid>:<gid> <file>
通过函数方式修改属主和属组:
#include <unistd.h>
int chown (
const char* path, // 文件路径
uid_t owner, // 属主ID
gid_t group // 属组ID
);
int fchown (
int fildes, // 文件描述符
uid_t owner, // 属主ID
gid_t group // 属组ID
);
int lchown (
const char* path, // 文件路径(不跟踪软链接)
uid_t owner, // 属主ID
gid_t group // 属组ID
);
成功返回 0,失败返回 -1。
注意:
1. 属主和属组 ID 取 -1 表示不修改。
2. 超级用户进程可以修改文件的属主和属组,
普通进程必须拥有该文件才可以修改其属主和属组。
3. truncate/ftruncate 修改文件的长度,截短丢弃,加长添零。
#include <unistd.h>
int truncate (
const char* path, // 文件路径
off_t length // 文件长度
);
int ftruncate (
int fd, // 文件描述符
off_t length // 文件长度
);
成功返回 0,失败返回 -1。
范例:trunc.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
int main (void) {
const char* text = "Hello, World !";
size_t size = (strlen (text) + 1) * sizeof (text[0]); // +1 给 \0 用
int fd = open ("trunc.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror ("open");
return -1;
}
if (ftruncate (fd, size) == -1) {
perror ("ftruncate");
return -1;
}
// 把文件和内存建立映射
void* map = mmap (NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED/*MAP_PRIVATE*/, fd, 0);
if (map == MAP_FAILED) {
perror ("mmap");
return -1;
}
// 往内存里写
memcpy (map, text, size);
printf ("%s\n", map);
// 解映射
munmap (map, size);
close (fd);
return 0;
}
运行测试:
#gcc trunc.c
#hexdump -C trunc.txt // 十六进制查看
#./a.out
Hello, World !
在 trunc.txt 建立好的基础上,我们写下面的测试程序,实现两个程序之间共享数据:
范例:mmap.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main (void) {
int fd = open ("trunc.txt", O_RDONLY);
if (fd == -1) {
perror ("open");
return -1;
}
struct stat st; // 用于下面求文件大小
if (fstat (fd, &st) == -1) {
perror ("fstat");
return -1;
}
// 两个内存映射到同一个文件
void* map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
perror ("mmap");
return -1;
}
printf ("%s\n", map);
munmap (map, st.st_size);
close (fd);
return 0;
}
运行测试:
#gcc mmap.c
#hexdump -C trunc.txt // 十六进制查看
#./a.out
Hello, World !
注意:对于文件映射,
私有映射 (MAP_PRIVATE) 将数据写到缓冲区而非文件中,只有自己可以访问。
而对于内存映射,
私有 (MAP_PRIVATE) 和公有 (MAP_SHARED) 没有区别,都是仅自己可以访问。
4. link/unlink/remove/rename
link: 创建文件的硬链接(目录条目)。
unlink: 删除文件的硬链接(目录条目)。
只有当文件的硬链接数降为 0 时,文件才会真正被删除。
若该文件正在被某个进程打开,其内容直到该文件被关闭才会被真正删除。
remove: 对文件同 unlink,对目录同 rmdir (不能删非空目录)。
rename: 修改文件/目录名。
#include <unistd.h>
int link (
const char* path1, // 文件路径
const char* path2 // 链接路径(硬链接)
);
int unlink (
const char* path // 链接路径
);
#include <stdio.h>
int remove (
const char* pathname // 文件/目录路径
);
int rename (
const char* old, // 原路径名
const char* new // 新路径名
);
成功返回 0,失败返回 -1。
5. symlink/readlink
symlink: 创建软链接;目标文件可以不存在,也可以位于另一个文件系统中。
里面存放着目标文件的名称;
readlink: 获取软链接文件本身(而非其目标)的内容。
open: 不能打开软链接文件本身,打开的是软链接目标。
#include <unistd.h>
int symlink (
const char* oldpath, // 文件路径(可以不存在)
const char* newpath // 链接路径(软链接)
);
成功返回 0,失败返回 -1。
ssize_t readlink (
const char* restrict path, // 软链接文件路径
char* restrict buf, // 缓冲区(存放目标文件路径)
size_t bufsize // 缓冲区大小
);
成功返回实际拷入缓冲区 buf 中软链接文件内容的字节数,失败返回 -1。
范例:slink.c
#include <stdio.h>
#include <limits.h>
int main (int argc, char* argv[]) {
if (argc < 3) {
fprintf (stderr, "用法:%s <文件> <软链接>\n", argv[0]);
return -1;
}
// 建立软链接
if (symlink (argv[1], argv[2]) == -1) {
perror ("symlink");
return -1;
}
char slink[PATH_MAX+1] = {0}; // 目标文件路径
if (readlink (argv[2], slink,
sizeof (slink) - sizeof (slink[0])) == -1) { // - sizeof (slink[0] 用于留一位给 \0
perror ("readlink");
return -1;
}
printf ("%s是%s的软链接。\n", argv[2], slink);
return 0;
}
运行测试:
#./a.out
#./a.out none.txt slink.txt
slink.txt 是 none.txt 的软链接。
slink.txt 大小为 8 字节,刚好是 none.txt 的名字大小;
而 none.txt 大小为 20 字节,里面存放的是真正的内容,所以较大;
6. mkdir/rmdir 创建/删除空目录
#include <sys/stat.h>
int mkdir (
const char* path, // 目录路径
mode_t mode // 访问权限,目录的执行权限(x)表示可进入
);
#include <unistd.h>
int rmdir (
const char* path // 目录路径
);
成功返回 0,失败返回 -1。
7. chdir/fchdir/getcwd
chdir/fchdir: 更改当前工作目录。
工作目录是进程的属性,只影响调用进程本身。
getcwd: 获取当前工作目录(绝对路径)。
#include <unistd.h>
int chdir (
const char* path // 工作目录路径
);
int fchdir (
int fildes // 工作目录描述符(由 open 函数返回)
);
成功返回 0,失败返回 -1。
char* getcwd (
char* buf, // 缓冲区
size_t size // 缓冲区大小
);
成功返回当前工作目录字符串指针,失败返回 NULL。
范例:dir.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
int main (void) {
char cwd[PATH_MAX+1]; // 用于装载当前目录
if (! getcwd (cwd, sizeof (cwd))) {
perror ("getcwd");
return -1;
}
printf ("当前工作目录:%s\n", cwd);
// 创建目录
if (mkdir ("work", 0755) == -1) {
perror ("mkdir");
return -1;
}
// 相当于 cd,进入目录
if (chdir ("work") == -1) {
perror ("chdir");
return -1;
}
if (! getcwd (cwd, sizeof (cwd))) {
perror ("getcwd");
return -1;
}
printf ("当前工作目录:%s\n", cwd);
if (mkdir ("empty", 0755) == -1) {
perror ("mkdir");
return -1;
}
if (rmdir ("empty") == -1) {
perror ("rmdir");
return -1;
}
// 如果没有删除 empty,下面这段代码就会报错,因为 work 目录非空;
if (rmdir ("../work") == -1) {
perror ("rmdir");
return -1;
}
return 0;
}
8. opendir/fdopendir/closedir/readdir/rewinddir/telldir/seekdir
opendir/fdopendir: 打开目录流。
closedir: 关闭目录流。
readdir: 读取目录流。
rewinddir: 复位目录流。
telldir: 获取目录流当前位置。
seekdir: 设置目录流当前位置。
#include <sys/types.h>
#include <dirent.h>
DIR* opendir (
const char* name // 目录路径
);
DIR* fdopendir (
int fd // 目录描述符(由open函数返回)
);
成功返回目录流指针,失败返回 NULL。
int closedir (
DIR* dirp // 目录流指针
);
成功返回 0,失败返回 -1。
struct dirent* readdir (
DIR* dirp // 目录流指针
);
成功返回下一个目录条目结构体的指针,
到达目录尾(不置 errno)或失败(设置 errno)返回 NULL。
struct dirent {
ino_t d_ino; // i节点号
off_t d_off; // 下一个条目的偏移量
// 注意是磁盘偏移量,而非内存地址偏移
unsigned short d_reclen; // 记录长度
unsigned char d_type; // 文件类型
char d_name[256]; // 文件名
};
d_type取值:
DT_DIR - 目录
DT_REG - 普通文件
DT_LNK - 软链接
DT_BLK - 块设备
DT_CHR - 字符设备
DT_SOCK - Unix域套接字
DT_FIFO - 有名管道
DT_UNKNOWN - 未知
范例:list.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
DIR* dp = opendir (argv[1]);
if (! dp) {
perror ("opendir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp)) {
switch (de -> d_type) {
case DT_DIR:
printf (" 目录:");
break;
case DT_REG:
printf (" 普通文件:");
break;
case DT_LNK:
printf (" 软链接:");
break;
case DT_BLK:
printf (" 块设备:");
break;
case DT_CHR:
printf (" 字符设备:");
break;
case DT_SOCK:
printf ("Unix域套接字:");
break;
case DT_FIFO:
printf (" 有名管道:");
break;
default:
printf (" 未知:");
break;
}
printf ("%s\n", de -> d_name);
}
if (errno) {
perror ("readdir");
return -1;
}
closedir (dp);
return 0;
}
练习:打印给定路径下的目录树
代码:tree.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
/*
#include <limits.h>
*/
int tree (const char* dir, size_t depth) {
DIR* dp = opendir (dir);
if (! dp) {
perror ("opendir");
return -1;
}
if (chdir (dir) == -1) { // 进入目录
perror ("chdir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp))
if (de -> d_type != DT_DIR)
printf ("%*s%s\n", depth * 2, "", de -> d_name); // 缩进
else if (strcmp (de -> d_name, ".") && // 不能进入本目录和父目录
strcmp (de -> d_name, "..")) {
printf ("%*s%s/\n", depth * 2, "", de -> d_name);
/*
char subdir[PATH_MAX+1];
sprintf (subdir, "%s/%s", dir, de -> d_name);
if (tree (subdir, depth + 1) == -1)
return -1;
*/
if (tree (de -> d_name, depth + 1) == -1)
return -1;
}
if (errno) { // errno 非零则表示出错
perror ("readdir");
return -1;
}
if (chdir ("..") == -1) {
perror ("chdir");
return -1;
}
closedir (dp);
return 0;
}
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
return tree (argv[1], 0);
}
回到头位置:
void rewinddir (
DIR* dirp // 目录流指针
);
得到当前位置:
long telldir (
DIR* dirp // 目录流指针
);
成功返回目录流的当前位置,失败返回 -1。
设置起始位置:
void seekdir (
DIR* dirp, // 目录流指针
long offset // 位置偏移量
);
+---------------------+ +-----------------------+
| v | v
+-------+----|---+-----+-------+ +-------+----|---+-----+--------+ +-------
| d_ino | d_off | ... | a.txt | ... | d_ino | d_off | ... | b.txt | ... | d_ino
+-------+-------+-----+-------+ +-------+--------+-----+-------+ +-------
^ ^
| -- readdir() -> |
范例:seek.c
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
int main (int argc, char* argv[]) {
if (argc < 2) {
fprintf (stderr, "用法:%s <目录>\n", argv[0]);
return -1;
}
DIR* dp = opendir (argv[1]);
if (! dp) {
perror ("opendir");
return -1;
}
seekdir (dp, 1722002057); // 设置起始位置
rewinddir (dp); // 回到头位置
long offset = telldir (dp);
if (offset == -1) {
perror ("telldir");
return -1;
}
errno = 0;
struct dirent* de;
for (de = readdir (dp); de; de = readdir (dp)) {
printf ("[%010d %010d] ", offset, de -> d_off);
switch (de -> d_type) {
case DT_DIR:
printf (" 目录:");
break;
case DT_REG:
printf (" 普通文件:");
break;
case DT_LNK:
printf (" 软链接:");
break;
case DT_BLK:
printf (" 块设备:");
break;
case DT_CHR:
printf (" 字符设备:");
break;
case DT_SOCK:
printf ("Unix域套接字:");
break;
case DT_FIFO:
printf (" 有名管道:");
break;
default:
printf (" 未知:");
break;
}
printf ("%s\n", de -> d_name);
if ((offset = telldir (dp)) == -1) {
perror ("telldir");
return -1;
}
}
if (errno) {
perror ("readdir");
return -1;
}
closedir (dp);
return 0;
}
相关文章推荐
- Matlab学习第二天 利用插值
- UGUI 代码 动态添加 Event Trigger 的事件
- 火云开发课堂 - 《Shader从入门到精通》系列 第十三节:在Shader中实现铅笔描边滤镜
- 张亦Excel VBA——基础篇
- 解析TCP/UDP协议的通讯软件
- spring 级联属性
- 自定义控件(视图)28期笔记09:自定义视图之继承自ViewGroup(仿ViewPager效果案例)
- web技术之负载均衡与缓存技术
- Nosql数据库——redis(五)主从复制
- java 时间字符串和时间戳(长整形long)之间的互转
- java基本类型和封装类型区别及应用
- 日期与字符串之间转换工具
- 随笔(2015.09)
- 实习小结十五:关于post文章页面的小结(倒数第二篇)
- uc笔记04---文件系统,文件常用命令(软/硬链接),文件描述符
- sendtoTarget()与sendtoMessage()
- java基本类型和封装类型区别及应用
- 网页导出excel
- [iOS]Core Data
- Linux 命令 - free: 显示系统的内存信息