UNIX环境编程学习笔记(12)——文件I/O之目录操作
lienhua34
2014-09-18
1 引言
在 UNIX 系统中,目录是一种特殊的文件类型。我们可以使用 open 函数来打开目录,获取文件描述符,然后调用 stat 函数来获取目录的属性信息,但是我们却不能够使用 read 函数来读取目录内容。例如,下面例子所示,
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#define BUF_LEN 2014
int
main(void)
{
int fd;
char buffer[BUF_LEN];
struct stat statbuf;
if ((fd = open("mydir", O_RDONLY)) < ) {
printf("open mydir error: %s\n", strerror(errno));
exit(-);
}
if (fstat(fd, &statbuf) < ) {
printf("fstat error: %s\n", strerror(errno));
exit(-);
}
if (S_ISDIR(statbuf.st_mode)) {
printf("mydir is directory\n");
}
if (read(fd, buffer, BUF_LEN) < ) {
printf("read mydir error: %s\n", strerror(errno));
exit(-);
}
printf("mydir: %s\n", buffer);
exit();
}
编译该程序,生成文件 readdir,然后运行 readdir,
lienhua34:demo$ ls -l
drwxrwxr-x lienhua34 lienhua34
9月 : mydir
lienhua34:demo$ gcc -o readdir readdir.c
lienhua34:demo$ ./readdir
mydir is directory
read mydir error: Is a directory
通过上面运行的结果,我们不难发现 read 函数读取目录时报错了。UNIX 提供了一套专门针对目录的操作函数。
2 创建目录
mkdir 函数提供了创建目录的功能。
#include <sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
返回值:若成功则返回0,若出错则返回-1.
mkdir 函数一个新的空目录。其中,. 和.. 目录项是自动创建的。这里指定的 mode 与进程的文件模式创建屏蔽字共同决定了新目录的文件访问权限(参考“文件访问权限的屏蔽和更改”。)
注:在“文件访问权限与进程访问控制”中,我们了解到目录的执行权限用于文件的搜索,所以在调用 mkdir 函数指定 mode 参数时至少设置1 个执行权限位。
3 删除目录
rmdir 函数可以删除一个空目录。空目录是只包含. 和.. 这两项的目录。
#include <unistd.h>
int rmdir(const char *pathname);
返回值:若成功则返回0,若出错则返回-1.
调用 rmdir 函数会使目录的链接计数减 1. 如果目录的链接计数减为0,且没有其他进程打开此目录,则释放目录占有的空间。如果在链接计数达到 0 时,存在进程打开了此目录,则在函数返回前删除以后一个链接及.和.. 项。另外,在此目录中不能再创建新文件。
例子 1:
下面程序是删除一个非空目录 mydir 失败的例子。
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int
main(void)
{
if (rmdir("mydir") < ) {
printf("rmdir mydir error: %s\n", strerror(errno));
} else {
printf("succ rmdir mydir");
}
exit();
}
编译该程序,生成 rmdirdemo,然后运行该文件,
lienhua34:demo$ ls -l mydir
总用量
-rw-rw-r-- lienhua34 lienhua34 9月 : file1
-rw-rw-r-- lienhua34 lienhua34 9月 : file2
lienhua34:demo$ gcc -o rmdirdemo rmdirdemo.c
lienhua34:demo$ ./rmdirdemo
rmdir mydir error: Directory not empty
例子 2:
下面程序删除空目录 emptydir,在进程尚未退出之前,在该目录下新建一个文件,
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
int
main(void)
{
int fd;
if ((fd = open("emptydir", O_RDONLY)) < ) {
printf("open emptydir error: %s\n", strerror(errno));
exit(-);
}
if (rmdir("emptydir") < ) {
printf("rmdir emptydir error: %s\n", strerror(errno));
exit(-);
}
printf("rmdir emptydir succ\n");
if (creat("emptydir/foo", S_IRUSR | S_IWUSR) < ) {
printf("creat error: %s\n", strerror(errno));
exit(-);
}
printf("creat succ\n");
exit();
}
编译该程序,生成文件 rmdirdemo,然后运行该文件,
lienhua34:demo$ ls -l emptydir
总用量
lienhua34:demo$ gcc -o rmdirdemo rmdirdemo.c
lienhua34:demo$ ./rmdirdemo
rmdir emptydir succ
creat error: No such file or directory
4 读取目录内容
对某个目录具有访问权限的任一用户都可读该目录,但是,之后内核才能够写目录。另外,目录的实际格式依赖于 UNIX 系统,特别是其文件系统的具体设计和实现。为了使应用程序与这些具体的实现细节隔离开,UNIX 系统提供了一套与读目录有关的例程。
#include <dirent.h>
DIR *opendir(const char *pathname);
返回值:若成功则返回真挚,若出错则返回NULL。struct dirent *readdir(DIR *dp);
返回值:若成功则返回指针,若在目录结尾或出错则返回NULL。void rewinddir(DIR *dp);
int close(DIR *dp);
返回值:若成功则返回0,若出错则返回-1.long telldir(DIR *dp);
返回值:与dp关联的目录中的当前位置。void seekdir(DIR *dp, long loc);
头文件 <dirent.h> 中定义的 dirent 结构与实现有关。不过,其至少包含下面两个成员:
struct dirent {
ino_t d_ino; /* i-node number */
char d_name[NAME_MAX + ]; /* filename */
}
opendir 函数打开一个目录,并执行初始化操作,使第一个 readir 读目录中的第一个目录项。
例子:
下面程序编译目录 mydir 下的所有目录项,并打印各个目录项的名字。
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
int
main(void)
{
DIR *dp;
struct dirent *dirp;
if ((dp = opendir("mydir")) == NULL) {
printf("opendir mydir error: %s\n", strerror(errno));
exit(-);
}
while ((dirp = readdir(dp)) != NULL) {
printf("%s\n", dirp->d_name);
}
if (closedir(dp) < ) {
printf("closedir error: %s\n", strerror(errno));
exit(-);
}
exit();
}
编译该程序,生成文件 readdir,然后运行该文件,
lienhua34:demo$ gcc -o readdir readdir.c
lienhua34:demo$ ./readdir
..
file2
.
file1
从上面程序的运行结果知道,读取目录中各目录项的顺序没有按照字母顺序进行排列。
5 切换进程的工作目录
每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点。进程可以调用 chdir 或 fchdir 函数更改当前工作目录。
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
两个函数的返回值:若成功则返回0,否则返回-1.
当前工作目录是进程的一个属性,更改进程的当前工作目录只影响调用 chdir 函数的进程本身,对其他进程则没有影响。
另外,UNIX 还提供了 getcwd 函数来获取进程的当前工作目录。
#include <unistd.h>
char *getcwd(char *buf, size_t size);
返回值:若成功则返回buf,若出错则返回NULL。
getcwd 函数的第一个参数是缓冲地址 buf,另一个是缓冲的长度 size(单位:字节)。该缓冲必须有足够的长度以容纳绝对路径名再加上一个 null终止字符。
例子:
下面程序先打印当前工作目录,然后调用 chdir 来切换工作目录,最后调用 getcwd 获取并打印新的工作目录。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define BUF_LEN 2014
int
main(void)
{
char buf[BUF_LEN];
if (getcwd(buf, BUF_LEN) < ) {
printf("getcwd error: %s\n", strerror(errno));
exit(-);
}
printf("cwd before chdir: %s\n", buf);
if (chdir("/home/lienhua34/program") < ) {
printf("chdir error: %s\n", strerror(errno));
exit(-);
}
if (getcwd(buf, BUF_LEN) < ) {
printf("getcwd error: %s\n", strerror(errno));
exit(-);
}
printf("cwd before chdir: %s\n", buf);
exit();
}
编译该程序,生成文件 cwddemo,然后运行该文件,
lienhua34:demo$ gcc -o cwddemo cwddemo.c
lienhua34:demo$ ./cwddemo
cwd before chdir: /home/lienhua34/program/c/apue/ch04/demo
cwd before chdir: /home/lienhua34/program
(done)
UNIX环境编程学习笔记(12)——文件I/O之目录操作的更多相关文章
- UNIX环境编程学习笔记(13)——文件I/O之标准I/O流
lienhua342014-09-29 1 标准 I/O 流 之前学习的都是不带缓冲的 I/O 操作函数,直接针对文件描述符的,每调用一次函数可能都会触发一次系统调用,单次调用可能比较快捷.但是,对于 ...
- UNIX环境编程学习笔记(7)——文件I/O之文件访问权限与进程访问控制
lienhua342014-09-02 1 文件的设置用户 ID位 和设置组 ID位 与进程相关联的 ID 如下表所示, 表 1: 与进程相关联的用户 ID 和组 ID 实际用户 ID 我们实际上是谁 ...
- UNIX环境编程学习笔记(6)——文件I/O之判断文件类型
lienhua342014-09-01 1 文件类型 我们平时最常接触的文件类型有普通文件(regular file)和目录(di-rectory file),但是 UNIX 系统提供了多种文件类型: ...
- UNIX环境编程学习笔记(27)——多线程编程(二):控制线程属性
lienhua342014-11-09 1 线程属性概括 POSIX 线程的主要属性包括 scope 属性.detach 属性.堆栈地址.堆栈大小.优先级.在头文件 pthread.h 中定义了结构体 ...
- UNIX环境编程学习笔记(10)——文件I/O之硬链接和符号链接
lienhua342014-09-15 1 文件系统数据结构 UNIX 文件系统通过 i 节点来存储文件的信息.如图 1 所示为一个磁盘柱面上的 i 节点和数据块示意图.其中 i 节点是一个固定长度的 ...
- UNIX环境编程学习笔记(9)——文件I/O之文件访问权限的屏蔽和更改
lienhua342014-09-10 1 文件访问权限 在文件访问权限和进程访问控制中,我们已经讲述过文件访问权限位,为了方便,我们重新列在下面, 表 1: 文件的 9 个访问权限位 st_mod ...
- UNIX环境编程学习笔记(8)——文件I/O之校验当前登录用户对文件的访问权限
lienhua342014-09-03 通过前面一篇随笔(文件访问权限与进程访问控制),我们知道内核校验文件的访问权限使用的是进程的有效用户 ID 和有效组 ID.但有时我们需要知道当前登录用户对某个 ...
- UNIX环境编程学习笔记(4)——文件I/O之dup复制文件描述符
lienhua342014-08-23 UNIX 提供了两个函数 dup 和 dup2 用于复制一个现存的文件描述符. #include <unistd.h> int dup(int fi ...
- UNIX环境编程学习笔记(3)——文件I/O之内核 I/O 数据结构
lienhua342014-08-27 内核使用三种数据结构表示打开的文件,分别是文件描述符表.文件表和 V 节点表. (1) 每个进程在进程表中都有一个记录项,记录项中包含有一张打开文件描述符表,每 ...
随机推荐
- java基础篇---内存分析
Java的并发采用的是共享内存模型(而非消息传递模型),线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变 ...
- Android 日历控件PickTime
最近做项目,需要设置用户的生日,所以做这样一个功能. 开始发觉自带的 DatePicker 很是不好用. 上代码: <DatePicker android:id="@+id/dpPic ...
- spark streaming checkpoint
Checkpoint机制 通过前期对Spark Streaming的理解,我们知道,Spark Streaming应用程序如果不手动停止,则将一直运行下去,在实际中应用程序一般是24小时*7天不间断运 ...
- 从零写Java Web框架——请求的处理DispatcherServlet
大概思路 继承 HttpServlet,实现 DispatcherServlet,拦截所有请求: DispatchServlet 重写 init()方法,负责初始化框架: 重写 service()方法 ...
- MySql生成日历表
mysql使用存储过程,创建日历表: 准备日历表: CREATE TABLE `m_dim_day` ( `ID` ) NOT NULL AUTO_INCREMENT, `DAY_ID` ) DEFA ...
- 【jquery】邮箱自动补全 + 上下翻动
最近在做通行证项目,里面注册模块有邮箱注册,需求方想要在输入 @ 后触发下拉框显示各个邮箱,效果如下: html 代码: <!DOCTYPE HTML> <html lang=&qu ...
- CentOS的Gearman安装
背景:用PHP做一些简单的上传是没有任何的问题,但是要做断点上传好像也是没有大问题,但要是并发的切片加断点上传可能就会有问题了哟.第一个问题是合并问题:如果一上传就合并,PHP老半天不返回是一个方面( ...
- Android跳转系统界面_大全集
1.跳转Setting应用列表(所有应用) Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS); ...
- Linux 文件编码格式转换
如果需要在Linux 中操作windows下的文件,那么经常遇到文件编码转换的问题. Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-. 查看文件编码 在vim 中 ...
- Ogre2.0 全新功能打造新3D引擎
不知当初是在那看到,说是Ogre2.0浪费了一个版本号,当时也没多想,以为没多大更新,一直到现在想做一个编辑器时,忽然想到要看下最新版本的更新,不看不知道,一看吓一跳,所以说,网络上的话少信,你不认识 ...