1 查看文件类型
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char * pathname, struct stat *buf);
All three return: 0 if OK, -1 on error
struct stat结构如下
unix 的文件类型(包含在st_mode中)
1> 普通文件,包含了某种类型的数据,可以是二进制的也可以是文本
2>目录文件,目录文件时包含了其他文件的文件名和链接的文件。
3>字符设备文件,对文件的读写以字符为单位的,没有缓冲区
4>块设备文件,对文件的读写以某个大小的块为单位,有缓冲区,写入与读出都是从缓冲区的读写
5>FIFO文件 也就是命名管道文件
6>符号连结:指向另一个文件的文件
示例:
#include "apue.h"
Int main(int argc, char *argv[])
{
int i;
struct stat buf;
char *ptr;
for (i = 1; i < argc; i++) {
printf("%s: ", argv[i]);
if (lstat(argv[i], &buf) < 0) {
err_ret("lstat error");
continue;
}
if (S_ISREG(buf.st_mode))
ptr = "regular";
else if (S_ISDIR(buf.st_mode))
ptr = "directory";
else if (S_ISCHR(buf.st_mode))
ptr = "character special";
else if (S_ISBLK(buf.st_mode))
ptr = "block special";
else if (S_ISFIFO(buf.st_mode))
ptr = "fifo";
else if (S_ISLNK(buf.st_mode))
ptr = "symbolic link";
else if (S_ISSOCK(buf.st_mode))
ptr = "socket";
else
ptr = "** unknown mode **";
printf("%s\n", ptr);
}
exit(0);
}
2 access函数–测试访问权限
#include <unistd.h>
int access(const char *pathname, int mode);
Returns: 0 if OK, -1 on error
mode取值
R_OK test for read permission
W_OK test for write permission
X_OK test for execute permission
F_OK test for existence of file
示例
#include "apue.h"
#include <fcntl.h>
Int main(int argc, char *argv[])
{
if (argc != 2)
err_quit("usage: a.out <pathname>");
if (access(argv[1], R_OK) < 0)
err_ret("access error for %s", argv[1]);
else
printf("read access OK\n");
if (open(argv[1], O_RDONLY) < 0)
err_ret("open error for %s", argv[1]);
else
printf("open for reading OK\n");
exit(0);
}
3 umask函数(为进程创建屏蔽字,并返回以前的值)
#include <sys/stat.h>
mode_t umask(mode_t cmask);
Returns: previous file mode creation mask
示例
#include "apue.h"
#include <fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
Int main(void)
{
umask(0);
if (creat("foo", RWRWRW) < 0)
err_sys("creat error for foo");
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("bar", RWRWRW) < 0)
err_sys("creat error for bar");
exit(0);
}
可以修改代码如下:拿走bar文件user的read和write权限
结果如下:
umask是从权限中“拿走”相应的位,且文件创建时不能赋予执行权限
umask 命令允许你设定文件创建时的缺省模式,对应每一类用户(文件属主、同组用户、其他用户)存在一个相应的umask值中的数字。对于文件来说,这一数字的最大值是6。系统不允许你在创建一个文本文件时就赋予它执行权限,必须在创建后用chmod命令增加这一权限。目录则允许设置执行权限,这样针对目录来说,umask中各个数字最大可以到7。
假设这次u m a s k值为0 2 2:
1) 文件的最大权限 rwx rwx rwx (777)
2 ) u m a s k值为0 2 2 — -w- -w-
3) 目录权限 rwx r-x r-x (755) 这就是目录创建缺省权限
4) 文件权限 rw- r– r– (644) 这就是文件创建缺省权限
4 chomd和fchomd函数
更改现有文件的访问权限
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int filedes, mode_t mode);
Both return: 0 if OK, -1 on error
Chomd在指定文件上操作,fchomd在已打开的文件上操作
示例:
#include "apue.h"
Int main(void)
{
struct stat statbuf;
/* turn on set-group-ID and turn off group-execute */
if (stat("foo", &statbuf) < 0)
err_sys("stat error for foo");
if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)//修改group的x权限
err_sys("chmod error for foo");
/* set absolute mode to "rw-r--r--" */
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
err_sys("chmod error for bar");
exit(0);
}
解释一下chmod(“foo”, (statbuf.st_mode & ~S_IXGRP) | S_ISGID) 这句话:
S_IXGRP=1(执行权限设定为1),取反为0.那么就是将组执行权限置空。
再“或”上S_ISGID,就是讲组执行权限置为S
S_ISGID表示(set group-id on execution),对应解释在(http://zhidao.baidu.com/link?url=04hmDw4WdWfPzD1oKNaFoK_0GgtZq4DO8wJ756h5W0Ml2c7GkeyhPpBwjU1AYUZbicJ74uRoiAriiIDvEr38rjp1tV0KnI1HMjJZU1OY_C3)
5 文件截短函数
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int ftruncate(int filedes, off_t length);
Both return: 0 if OK, 1 on error
6 link, unlink, remove, rename函数
#include <unistd.h>
int link(const char *existingpath, const char *newpath);
Returns: 0 if OK, -1 on error
此函数创建一个newpath,引用现有的文件existingpath。如果newpath存在,返回-1。只创建newpath中的最后一个分量,路径中的其它部分应该存在
#include <unistd.h>
int unlink(const char *pathname);
Returns: 0 if OK, -1 on error
此函数删除目录项,并将pathname所引用的文件链接计数减1.如果该文件还有其他链接,可以通过其他链接访问该数据
#include <stdio.h>
int remove(const char *pathname);
Returns: 0 if OK, 1 on error
移除链接。对于文件,相当于unlink;对于目录,相当于rmdir
#include <stdio.h>
int rename(const char *oldname, const char *newname);
Returns: 0 if OK, 1 on error
给文件或者目录更名
7 utime函数(一个文件的访问和修改时间可用它更改)
#include <utime.h>
int utime(const char *pathname, const struct utimbuf *times);
Returns: 0 if OK, 1 on error
struct utimbuf数据结构如下:
struct utimbuf {
time_t actime; /* access time */
time_t modtime; /* modification time */
}
下面的代码使用带O_TRUNC选项的open函数将文件长度截短为0,但不更改访问和修改时间。为了做到这一点,先用stat获取文件当前状态(包括时间),然后截短,最后用utime复位
#include "apue.h"
#include <fcntl.h>
#include <utime.h>
Int main(int argc, char *argv[])
{
int i, fd;
struct stat statbuf;
struct utimbuf timebuf;
for (i = 1; i < argc; i++) {
if (stat(argv[i], &statbuf) < 0) { /* fetch current times */
err_ret("%s: stat error", argv[i]);
continue;
}
if ((fd = open(argv[i], O_RDWR | O_TRUNC)) < 0) { /* truncate */
err_ret("%s: open error", argv[i]);
continue;
}
close(fd);
timebuf.actime = statbuf.st_atime;
timebuf.modtime = statbuf.st_mtime;
if (utime(argv[i], &timebuf) < 0) { /* reset times */
err_ret("%s: utime error", argv[i]);
continue;
}
}
exit(0);
}
8 读目录
#include <dirent.h>
DIR *opendir(const char *pathname);
Returns: pointer if OK, NULL on error
struct dirent *readdir(DIR *dp);
Returns: pointer if OK, NULL at end of directory or error
void rewinddir(DIR *dp);
int closedir(DIR *dp);
Returns: 0 if OK, 1 on error
long telldir(DIR *dp);
Returns: current location in directory associated with dp
void seekdir(DIR *dp, long loc);
用法如下:
#include "apue.h"
#include <dirent.h>
#include <limits.h>
/* function type that is called for each filename */
typedef int Myfunc(const char *, const struct stat *, int);
static Myfunc myfunc;//相当于myfunc(const char *, const struct stat *, int);统计各种类型的文件的数量
static int myftw(char *, Myfunc *);
static int dopath(Myfunc *);
static long nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
int main(int argc, char *argv[])
{
int ret;
if (argc != 2)
err_quit("usage: ftw <starting-pathname>");
ret = myftw(argv[1], myfunc); /* does it all */
ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
if (ntot == 0)
ntot = 1; /* avoid divide by 0; print 0 for all counts */
printf("regular files = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot);
printf("directories = %7ld, %5.2f %%\n", ndir, ndir*100.0/ntot);
printf("block special = %7ld, %5.2f %%\n", nblk, nblk*100.0/ntot);
printf("char special = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot);
printf("FIFOs = %7ld, %5.2f %%\n", nfifo, nfifo*100.0/ntot);
printf("symbolic links = %7ld, %5.2f %%\n", nslink, nslink*100.0/ntot);
printf("sockets = %7ld, %5.2f %%\n", nsock, nsock*100.0/ntot);
exit(ret);
}
#define FTW_F 1 /* file other than directory */
#define FTW_D 2 /* directory */
#define FTW_DNR 3 /* directory that can't be read */
#define FTW_NS 4 /* file that we can't stat */
static char *fullpath; /* contains full pathname for every file */
static int myftw(char *pathname, Myfunc *func)
{
int len;
fullpath = path_alloc(&len); /* malloc's for PATH_MAX+1 bytes */
strncpy(fullpath, pathname, len); /* protect against */
fullpath[len-1] = 0; /* buffer overrun */
return(dopath(func));
}
//path_alloc在网上有详细的解释http://www.docin.com/p-634598991.html
//注意里面的size=PATH_MAX+1
//所以才有了fullpath[len-1] = 0;这句
static int dopath(Myfunc* func)//遍历fullpath下的每个文件并统计,包括stat error和directory这两种情况
{
struct stat statbuf;
struct dirent *dirp;
DIR *dp;
int ret;
char *ptr;
if (lstat(fullpath, &statbuf) < 0) /* stat error */
return(func(fullpath, &statbuf, FTW_NS));
if (S_ISDIR(statbuf.st_mode) == 0) /* not a directory */
return(func(fullpath, &statbuf, FTW_F));
if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
return(ret);
ptr = fullpath + strlen(fullpath); /* point to end of fullpath */
*ptr++ = '/';
*ptr = 0;
if ((dp = opendir(fullpath)) == NULL) /* can't read directory */
return(func(fullpath, &statbuf, FTW_DNR));
while ((dirp = readdir(dp)) != NULL)
{
if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
continue; /* ignore dot and dot-dot */
strcpy(ptr, dirp->d_name); /* append name after slash */
if ((ret = dopath(func)) != 0) /* recursive */
break; /* time to leave */
}
ptr[-1] = 0; /* erase everything from slash onwards */
if (closedir(dp) < 0)
err_ret("can't close directory %s", fullpath);
return(ret);
}
static int myfunc(const char *pathname, const struct stat *statptr, int type)//统计各种类型的文件的数量
{
switch (type) {
case FTW_F:
switch (statptr->st_mode & S_IFMT) {
case S_IFREG: nreg++; break;
case S_IFBLK: nblk++; break;
case S_IFCHR: nchr++; break;
case S_IFIFO: nfifo++; break;
case S_IFLNK: nslink++; break;
case S_IFSOCK: nsock++; break;
case S_IFDIR:
err_dump("for S_IFDIR for %s", pathname);
/* directories should have type = FTW_D */
}
break;
case FTW_D:
ndir++;
break;
case FTW_DNR:
err_ret("can't read directory %s", pathname);
break;
case FTW_NS:
err_ret("stat error for %s", pathname);
break;
default:
err_dump("unknown type %d for pathname %s", type, pathname);
}
return(0);
}
9 chdir, fchdir, getcwd函数
可以更改目录
#include <unistd.h>
int chdir(const char *pathname);
int fchdir(int filedes);
Both return: 0 if OK, 1 on error
因为当前目录是进程的一个属性,所以只影响chdir本身。这就意味着下面这段代码不会产生我们希望的结果
#include "apue.h"
int main(void)
{
if (chdir("/tmp") < 0)
err_sys("chdir failed");
printf("chdir to /tmp succeeded\n");
exit(0);
}
编译程序会得到下列结果:
$ pwd
/usr/lib
$ mycd
chdir to /tmp succeeded
$ pwd
/usr/lib
由此可见当前目录并没有改变,是因为shell创建了一个子进程来执行这个程序。要想改变目录,必须要让shell去执行,cd命令的执行程序直接包含在shell里面。