Linux程序设计-2.文件和目录

2. 文件和目录

2.1 文件

2.1.1 获取文件状态stat()

帮助手册:man 2 stat
包含头文件:

  • #include <sys/types.h>
  • #include <sys/stat.h>
  • #include <unistd.h>

函数原型:

  • int stat(const char *pathname, struct stat *statbuf);
参数说明
pathname文件名
statbuf文件状态结构体
return成功:0
失败:-1,设置errno

文件状态结构体

struct stat {
	dev_t     st_dev;         /* 文件的设备编号 */
	ino_t     st_ino;         /* 索引节点号 */
    mode_t    st_mode;        /* 文件类型和权限 */
    nlink_t   st_nlink;       /* 硬连接数 */
    uid_t     st_uid;         /* 所有者用户ID */
    gid_t     st_gid;         /* 所有者组ID */
    dev_t     st_rdev;        /* 设备ID(特殊文件) */
    off_t     st_size;        /* 大小(字节) */
    blksize_t st_blksize;     /* 文件系统的I/O缓冲区大小 */
    blkcnt_t  st_blocks;      /* 分配的512B块数 */
    struct timespec st_atim;  /* 最近访问 */
    struct timespec st_mtim;  /* 最近更改 */
    struct timespec st_ctim;  /* 最近改动 */
    #define st_atime st_atim.tv_sec      /* 向后兼容性 */
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
};
struct timespec {
	__kernel_time_t	tv_sec;		/* 秒 */
	long			tv_nsec;	/* 纳秒 */

st_mode 定义了下列数种情况::

说明
S_IFMT0170000文件类型的位遮罩
S_IFSOCK0140000scoket
S_IFLNK0120000符号连接
S_IFREG0100000一般文件
S_IFBLK0060000区块装置
S_IFDIR0040000目录
S_IFCHR0020000字符装置
S_IFIFO0010000先进先出
S_ISUID04000文件的(set user-id on execution)位
S_ISGID02000文件的(set group-id on execution)位
S_ISVTX01000文件的sticky位
S_IRUSR00400文件所有者具可读取权限
S_IWUSR00200文件所有者具可写入权限
S_IXUSR00100文件所有者具可执行权限
S_RWXU00700文件所有者具有读,写和执行权限
S_IRGRP00040用户组具可读取权限
S_IWGRP00020用户组具可写入权限
S_IXGRP00010用户组具可执行权限
S_IROTH00004其他用户具可读取权限
S_IWOTH00002其他用户具可写入权限
S_IXOTH00001其他用户具可执行权限

上述的文件类型在POSIX中定义了检查这些类型的宏定义:

说明
S_ISLNK (st_mode)判断是否为符号连接
S_ISREG (st_mode)是否为一般文件
S_ISDIR (st_mode)是否为目录
S_ISCHR (st_mode)是否为字符装置文件
S_ISBLK (st_mode)是否为块设备
S_ISSOCK (st_mode)是否为socket
2.1.1.1 通过uid获取用户名getpwuid()

struct passwd *getpwuid(uid_t uid);
包含头文件:
#include <sys/types.h>
#include <pwd.h>

struct passwd {
	char	*pw_name;		/* 用户名 */
	char	*pw_passwd		/* 用户密码 */
	char	*pw_gecos;		/* 用户信息 */
	char	*pw_dir;		/* 家目录 */
	char	*pw_sheel;		/* shell程序 */
	uid_t	pw_uid;			/* 用户ID */
	gid_t	pw_gid;			/* 组ID */
};
2.1.1.2 通过gid获取组名getgrgid

struct group *getgrgid(gid_t gid);
包含头文件:
#include <sys/tyeps.h>
#include <grp.h>

struct group {
	char	*gr_name;		/* 组名 */
	char	*gr_passwd;		/* 组密码 */
	char	**gr_mem;		/* 指向组成员名称的以NULL结尾的指针数组 */
	git_t	gr_gid;			/* 组ID */
};
2.1.1.3 通过秒数获取本地时间localtime

struct tm *localtime(const time_t *timep);

struct tm {
	int tm_sec;		/* 秒(0-60) */
	int tm_min;		/* 分(0-59) */
	int tm_hour;	/* 时(O-23) */
	int tm_mday;	/* 天(1-31) */
	int tm_mon;		/* 月(0-11) */
	int tm_year;	/* 年-1900 */
	int tm_wday;	/* 星期(0-6,Sun=0) */
	int tm_yday;	/* 一年中第几天(0-365,1 Jan = 0) */
	int tm_isdst;	/* 夏令时间 */
};

查看文件信息示例代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>

int main(int argc, char* argv[])
{
	struct stat sb;
	stat(argv[1], &sb);
	char stmode[11] = { 0 };
	// 解析st_mode
	memset(stmode, '-', sizeof(stmode)-1);
	if(S_ISDIR(sb.st_mode)) stmode[0] = 'd';
	if(S_ISCHR(sb.st_mode)) stmode[0] = 'c';
	if(S_ISBLK(sb.st_mode)) stmode[0] = 'b';
	if(S_ISFIFO(sb.st_mode)) stmode[0] = 'p';
	if(S_ISLNK(sb.st_mode)) stmode[0] = 'l';
	if(S_ISSOCK(sb.st_mode)) stmode[0] = 's';

	if(sb.st_mode & S_IRUSR) stmode[1] = 'r';
	if(sb.st_mode & S_IWUSR) stmode[2] = 'w';
	if(sb.st_mode & S_IXUSR) stmode[3] = 'x';

	if(sb.st_mode & S_IRGRP) stmode[4] = 'r';
	if(sb.st_mode & S_IWGRP) stmode[5] = 'w';
	if(sb.st_mode & S_IXGRP) stmode[6] = 'x';

	if(sb.st_mode & S_IROTH) stmode[7] = 'r';
	if(sb.st_mode & S_IWOTH) stmode[8] = 'w';
	if(sb.st_mode & S_IXOTH) stmode[9] = 'x';
	
	struct tm *filetm = localtime(&sb.st_atim.tv_sec);
	char timebuf[20] = { 0 };
	sprintf(timebuf, "%d月 %d %02d:%02d", filetm->tm_mon+1,filetm->tm_mday, filetm->tm_hour, filetm->tm_min);

	printf("%s %ld %s %s %ld %s %s\n",stmode, sb.st_nlink, getpwuid(sb.st_uid)->pw_name, getgrgid(sb.st_gid)->gr_name, sb.st_size, timebuf, argv[1]);
	return 0;
}

lstata()和stat()的区别:
stat()有穿透效果,当遇到软连接会通过软连接找到硬连接
lstat()没有穿透效果

2.1.2 判断有效用户对一个文件的权限或文件是否存在access()

帮助手册:man 2 access
包含头文件:

  • #include <unistd.h>

函数原型:
int access(const char *pathname, int mode);

参数说明
pathname文件路径
modeR_OK:读
W_OK:写
X_OK:执行
F_OK:存在
return成功:0
失败:-1

示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	if(access(argv[1], R_OK) == 0) printf("%s read ok!\n", argv[1]);
	if(access(argv[1], W_OK) == 0) printf("%s write ok!\n", argv[1]);
	if(access(argv[1], X_OK) == 0) printf("%s execute ok!\n", argv[1]);
	if(access(argv[1], F_OK) == 0) printf("%s existence!\n", argv[1]);
	return 0;
}

2.1.3 修改文件权限chmod()

帮助手册:man 2 chmod
包含头文件:

  • #include <sys/stat.h>

函数原型:
int chmod(const char *pathname, mode_t mode);

参数说明
pathname文件路径
mode新的权限
return成功:0
失败:-1,并设置errno

2.1.4 改变文件所有权chown()

帮助手册:man 2 chown
包含头文件:

  • #include <unistd.h>

函数原型:
int chown(const char *pathname, uid_t owner, gid_t group);f

参数说明
pathname文件路径
owenr用户ID(/etc/passwd)
group组ID(/etc/group)
return成功:0
失败:-1,并设置errno

2.1.5 截断一个文件到一个指定长度truncate()

帮助手册:man 2 truncate
包含头文件:

  • #include <unistd.h>
  • #include <sys/types.h>

函数原型
int truncate(const char *path, off_t length);

参数说明
path文件路径
length截断长度
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    truncate(argv[1], 1024);
    return 0;
}

2.1.6 创建硬连接link()

帮助手册:man 2 link
包含头文件:

  • #include <unistd.h>

函数原型:
int link(const char *oldpath, const char *newpath);

参数说明
oldpath原路径
newpath新路径
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	link(argv[1], argv[2]);
	return 0;
}

2.1.7 创建软连接symlink()

帮助手册:man 2 symlink
包含头文件:

  • #include <unistd.h>

函数原型:
int symlink(const char *target, const char *linkpath);

参数说明
target原目标
linkpath软连接路径
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	symlink(argv[1], argv[2]);
	return 0;
}

2.1.8 读一个软连接readlink()

帮助手册:man 2 readlink
包含头文件:
-#include <unistd.h>

函数原型:
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

参数说明
pathname软连接路径
buf缓冲区
bufsiz缓冲区大小
return成功:大小
失败:-1,设置errno

示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	char buf[32] = { 0 };
	readlink(argv[1], buf, sizeof(buf));
	printf("buf is %s\n", buf); # argv[1]
	return 0;
}

2.1.9 删除一个连接unlink()

帮助手册:man 2 unlink
包含头文件:

  • #include <unistd.h>

函数原型:
int unlink(const char *pathname);

参数说明
pathname路径
return成功:0
失败:-1,并设置errno
#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	unlink(argv[1]);
	return 0;
}

注:当文件被打开,但是所有硬连接被unlink,当打开这个文件的进程结束后,这个文件才会被删除。

2.1.10 更改一个文件或目录的名字或位置rename()

帮助手册:man 2 rename
包含头文件:

  • #include <stdio.h>

函数原型:
int rename(const char *oldpath, const char *newpath);

参数说明
oldpath原路径
newpath新路径
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>

int main(int argc, char* argv[])
{
	rename(argv[1], argv[2]);
	return 0;
}

2.2 目录

2.2.1 获取当前工作路径getcwd()

帮助手册:man 2 getcwd
包含头文件:

  • #include <unistd.h>

函数原型:
char *getcwd(char *buf, size_t size);

参数说明
buf传出缓冲区
size缓冲区大小
return成功:当前工作路径的指针
失败:NULL,并设置errno

2.2.2 改变工作目录chdir()

帮助手册:man 2 getcwd
包含头文件:

  • #include <unistd.h>

函数原型:
char *chdir(char *path);

参数说明
path新路径
return成功:0
失败:-1,并设置errno

2.2.3 创建目录mkdir()

帮助手册:man 2 mkdir
包含头文件:

  • #include <sys/stat.h>
  • #include <sys/types.h>

函数原型:
int mkdir(const char *pathname, mode_t mode);

参数说明
pathname目录名
mode目录权限
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	char buf[256] = { 0 };
	chdir("../");
	getcwd(buf, sizeof(buf));
	printf("current working path: %s\n", buf);
	mkdir("newdir", 0777);
	return 0;
}

2.2.4 删除空目录rmdir()

帮助手册:man 2 rmdir
包含头文件:

  • #include <unistd.h>

函数原型:
int rmdir(const char *pathname);

参数说明
pathname目录路径
return成功:0
失败:-1并设置errno

2.2.5 打开目录opendir()

帮助手册:man opendir`
包含头文件:

  • #include <sys/types.h>
  • #include <dirent.h>

函数原型:
int rmdir(const char *pathname);

参数说明
pathname目录路径
return成功:目录流的指针
失败:NULL,并设置errno

2.2.4 读目录readdir()

帮助手册:man 3 readdir
包含头文件:

  • #include <dirent.h>

函数原型:
struct dirent *readdir(DIR *dirp);

参数说明
dirp目录流的指针
return成功:下一个目录进入点
失败:NULL,并设置errno
读到目录文件尾:NULL
struct dirent {
	ino_t          d_ino;       /* Inode号 */
	off_t          d_off;       /* 目录文件开头至此目录进入点的位移 */
	unsigned short d_reclen;    /* d_name的长度 */
	unsigned char  d_type;      /* d_name所指的文件类型 */
	char           d_name[256]; /* 文件名 */
};

d_type值说明:

说明
DT_BLK块设备
DT_CHR字符设备
DT_DIR目录
DT_FIFO管道
DT_LNK软连接
DT_REG普通文件
DT_SOCKsock
DT_UNKNOWN未知类型

2.2.5 关闭目录closedir()

帮助手册:man 3 closedir
包含头文件:

  • #include <sys/types.h>
  • #include <dirent.h>

函数原型:
int closedir(DIR *dirp);

参数说明
dirp目录流的指针
return成功:0
失败:-1,并设置errno

示例:

#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>

int count = 0;

int DirCount(char *dirname)
{
	DIR *dirp = opendir(dirname);
	if(dirp == NULL)
		return -1;
	struct dirent *dentp = NULL;
	while((dentp = readdir(dirp)) != NULL)
	{
		if(dentp->d_type == DT_DIR)
		{
			if(strcmp(".", dentp->d_name) == 0 || strcmp("..", dentp->d_name) == 0)
				continue;
			char newdirname[1024] = { 0 };
			sprintf(newdirname, "%s/%s", dirname, dentp->d_name);
			DirCount(newdirname);
		}
		printf("%s/%s\n", dirname, dentp->d_name);
		count++;
	}
	closedir(dirp);
	return 0;
}

int main(int argc, char* argv[])
{
	DirCount(argv[1]);
	printf("count = %d\n", count);
	return 0;
}

2.2.6 重设读取目录的位置为开头位置rewinddir()

帮助手册:man 3 rewinddir
包含头文件:

  • #include <sys/types.h>
  • #include <dirent.h>

函数原型:
void rewinddir(DIR *dirp);

参数说明
dirp目录流的指针
returnvoid

2.2.7 获取目录流的读取位置telldir()

帮助手册:man 3 telldir
包含头文件:

  • #include <sys/types.h>
  • #include <dirent.h>

函数原型:
long telldir(DIR *dirp);

参数说明
dirp目录流的指针
return成功:下一个读取位置
失败:-1,并设置errno

2.2.8 设置下次读取目录的位置seekdir()

帮助手册:man 3 seekdir
包含头文件:

  • #include <dirent.h>

函数原型:
void seekdir(DIR *dirp, long loc);

参数说明
dirp目录流的指针
loc距离目录文件开头的偏移量
returnvoid

2.3 错误信息errno

包含头文件:

  • /usr/include/asm-generic/errno-base.h
  • /usr/include/asm-generic/errno.h
  • /usr/include/errno.h
  • etc

查找errno头文件
sudo find /usr/ -name "errno*.h"

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT灰猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值