文件和目录
三、文件和目录
相关函数
1、stat()
函数功能:获得文件的详细信息,然后存到结构体里。
//man 2 stat
int stat(const char *pathname, struct stat *statbuf);
//返回值:成功-->0 失败--> -1
stat默认展开符号链接 lstat不展开符号链接(一般用lstat)
struct stat 结构体成员:
struct stat {
dev_t st_dev; /* ID of device containing file 文件本身存储的设备号*/
ino_t st_ino; /* Inode number 线程号*/
mode_t st_mode; /* File type and mode 文件类型 */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) 针对驱动的字符设备和块设备文件的主次设备号*/
off_t st_size; /* Total size 文件总大小, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O 块大小 */
blkcnt_t st_blocks; /* Number of 512B blocks allocated 当前文件占用了多少个512个快*/
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
//man inode "st_mode"
inode --> “st_mode” 用宏进行判断文件类型
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.)
应用
stat(pathname, &sb);
if (S_ISREG(sb.st_mode))
{
/* Handle regular file */
}
1.1 获取文件长度代码演示:
off_t flen(const char *fname)
{
struct stat statres;
if(stat(fname,&statres) < 0)
{
perror("stat()");
exit(1);
}
return statres.st_size;
}
int main(int argc,char *argv[])
{
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
printf("%lld\n",(long long)flen(argv[1]));
exit(0);
}
1.2 必须在包含头文件之前实现宏的定义情况
man fseeko
CFLAGS+=-D_FILE_OFFSET_BITS=64 (CFLAGS是编译选项)
//写makefile:
gcc -D_FILE_OFFSET_BITS=64
//在命令行:
1.3 权限:st_mode
man inode
mode_t st_mode 高四位表示文件类型,
获取文件类型:将拿到的文件类型 & 那些宏 如果为真,就表明是那2些文件
用宏测测试文件类型。
S_ISUID 04000 set-user-ID bit
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and
execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
1.4 文件占用大小的问题
命令:du 打印文件在磁盘中真正的占用空间
off_t st_size; /* Total size 文件总大小, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O 块大小 */ blkcnt_t st_blocks; /* Number of 512B blocks allocated 当前文件占用了多少个512个快*/ //size就是一个属性而已,跟后面没有关联
先创建一个5G的空洞文件,然后cp
会发现cp复制的很快,因为cp的原理是先read,cout+=1024,如果全是则不write
1.5 S_ISDIR(m)
判断是否为目录
2、opendir() && readdir()
函数功能:打开一个目录
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
struct dirent *readdir(DIR *dirp);
//返回值:成功-->DIR * 失败-->NULL
代码应用:
#define PATH "/etc"
int main()
{
DIR *dp;
struct dirent *cur;
dp = opendir(PATH);
if(dp == NULL)
{
perror("opendir()");
exit(1);
}
while((cur = readdir(dp)) != NULL)
{
puts(cur->d_name);
}
closedir(dp);
exit(0);
}
3、glob()-读目录
函数功能:用来匹配通配符指定模式的文本值
int glob(const char *pattern, int flags,int (*errfunc) (const char *epath, int eerrno),glob_t *pglob);
//返回值:成功 --> 0 不成功 --> 非0
void globfree(glob_t *pglob); //释放pglob
参数:
- pattern:通配符指定模式(要解析的通配符)
- flags:有什么特殊要求
- 函数:出错的详细信息(在glob出错时调用)
- pglob:存放结果的空间(前两个,计数器,存放结果的数组)
代码应用:
#define PAT "/etc/a*.conf"
int myerrfun(const char *epath, int eerrno)
{
fprintf(stderr,"%s:%s\n",epath,strerror(eerrno);
}
int main()
{
glob_t globres;
int i,err;
err = glob(PAT, 0, NULL/*myerrfun*/, &globres);
if(err)
{
printf("ERROR CODE:%d\n",err);
exit(1);
}
for(i = 0 ; i < globres.gl_pathc ; i++)
{
puts(globres.gl_pathv[i]);
}
globfree(&globres);
exit(0);
}
*glob_t pglob结构体:
typedef struct {
size_t gl_pathc; /* Count of paths matched so far 数量 */
char **gl_pathv; /* List of matched pathnames. 路径*/
size_t gl_offs; /* Slots to reserve in gl_pathv. */
} glob_t;
常用flags:
int flags | 含义 |
---|---|
GLOB_APPEND | 追加模式(追加到glob_t的尾部) |
GLOB_NOCHACK | 不检查 |
4、getcwd()
获取当前路径
char *getcwd(char *buf, size_t size);//返回值:
5、getpwuid()
函数功能:给你一个用户的ID,得到全部用户的信息。
struct passwd *getpwuid(uid_t uid);
struct passwd *pwdname;
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
6、getgrgid()
函数功能:给你一个组ID,得到全部的组信息。
struct group *getgrgid(gid_t gid);
struct group *pwdgroup;
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
7、truncate()
文件截断:将一个现有文件长度截断为length,如果该文件以前的长度大于length,则超过length以外的数据将不能够再访问,如果以前的长度小于length,文件长度将增加,文件尾端数据将读0(空洞)
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
8、atoi()
函数功能:把一个字符串转换成int
int atoi(const char *nptr);
//The atoi() function converts the initial portion of the string pointed to by nptr to int.
拓展+练习
1、请写一个程序删除一个文本文件的第十行
4.13 trunstat
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
FILE *fd1,*fd2;
int i=1,j,len_10,oldlen,num_10 = 0;
char *linebuf = NULL,arr[20];
ssize_t linesize = 0; //len_10
char str[100]; //fgets
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
fd1 = fopen(argv[1],"r");
fd2 = fopen(argv[1],"r+");
fseek(fd1,0,SEEK_END);
oldlen = ftell(fd1); //文件总大小
printf("oldlen = %d\n",oldlen);
rewind(fd1);
while(1)
{
if(getline(&linebuf, &linesize, fd1) < 0 || i == 10)
{
len_10 = strlen(linebuf); //删除前第十行长度
printf("old_len_10 = %d\n",len_10);
break;
}
num_10 = num_10 + strlen(linebuf); //第十行的位置
i++;
}
fseek(fd1,num_10+len_10,SEEK_SET); //11
fseek(fd2,num_10,SEEK_SET); //10
printf("delele\n");
while(fgets(str,20,fd1) != NULL) //11 --> 10
fputs(str,fd2);
truncate(argv[1],oldlen-len_10); //delete
rewind(fd1);
while(1) //验证
{
if(getline(&linebuf, &linesize, fd1) < 0 || j == 10)
{
printf("new_len_10 = %ld\n",strlen(linebuf)); //删除后的文件的第十行长度
break;
}
i++;
}
exit(0);
fclose(fd1);
fclose(fd2);
}
2、实现mudu
ls -a
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#define PATH "./"
int path_no_loop(const char *path)
{
char *pos;
pos = strrchr(path,'/');
if(strcmp(pos+1,".") == 0 || strcmp(pos+1,"..") == 0 )
return 0;
return 1;
}
int64_t my_du(const char*path)
{
struct stat statres;
int i;
int64_t sum = 0;
char nextpath[1024];
glob_t globres;
if(lstat(path,&statres) < 0)
{
perror("lstat()");
exit(1);
}
//not is dir
if(!S_ISDIR(statres.st_mode))
return statres.st_blocks;
//is dir
strncpy(nextpath,path,1024);
strncat(nextpath,"/*",1024);
glob(nextpath,0,NULL,&globres);
strncpy(nextpath,path,1024);
strncat(nextpath,"/.*",1024);
glob(nextpath,GLOB_APPEND,NULL,&globres);
for( i=0;i < globres.gl_pathc;i++)
{
if(path_no_loop(globres.gl_pathv[i]))
sum += my_du(globres.gl_pathv[i]);
printf("%d %s\n",statres.st_blocks/2,globres.gl_pathv[i]);
}
sum += statres.st_blocks;
return sum;
}
int main(int argc,char *argv[])
{
int i,err,num = 0;
glob_t globres;
printf("%ld\n",my_du(argv[1])/2);
exit(0);
}
3、strrchr()
在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
char *strrchr(const char *str, int c)
//该函数返回 str 中最后一次出现字符 c 的位置。如果未找到该值,则函数返回一个空指针。
char *pos;
pos = strrchr(globres.gl_pathv[i],'/');
参数:
- str – C 字符串。
- c – 要搜索的字符。以 int 形式传递,但是最终会转换回 char 形式。
tail -f 以动态的形式查看文件尾部的变化
4、strchr()
在参数 s 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
char *strchr(const char *s, int c);
//该函数返回在字符串 str 中第一次出现字符 c 的位置,如果未找到该字符则返回 NULL。
5、广义表转换成二叉树
广义表 -----> tree.log
struct node_st *load(FILE *fp)
{
int ch;
ch = fgetc(fp);
struct node_st *root;
if(ch != '(')
{
fprintf(stderr,"read error().\n");
return NULL;
}
ch = fgetc(fp);
if(ch == ')')
return NULL;
root = malloc(sizeof(*root));
root->data = ch;
root->l = load(fp);
root->r = load(fp);
fgetc(fp); //(
return root;
}
struct node_st *tree_list(const char *path)
{
FILE *fp;
struct node_st *root;
fp = fopen(path,"r");
/* if error*/
root = load(fp);
fclose(fp);
return root;
}