【本文谢绝转载,原文来自http://990487026.blog.51cto.com】
Linux系统开发 文件操作 ext2文件系统了解 stat()函数 access()函数 chmod()函数 utime()函数 truncate()函数 link()硬链接函数 symlink()软链接函数 readlink()函数 unlink函数 rename函数() 目录操作 chdir()/fchdir() getcwd/getwd()/get_current_dir_name() pathconf() opendir() readdir() dup()/dup2() 练习:
深入解析 ext2 文件系统
stat函数获取文件大小
chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include //#include int main(int argc,char **argv) { struct stat s_buf; if(argc < 2) { printf("参数不够\n"); exit(1); } if(stat(argv[1],&s_buf) < 0) { perror("stat"); exit(2); } printf("文件名:%s\n",argv[1]); printf("文件大小:%ld字节 \n",s_buf.st_size); } // int stat(const char *pathname, struct stat *buf); // int fstat(int fd, struct stat *buf); // int lstat(const char *pathname, struct stat *buf); // lstat不跟踪符号链接 // // struct stat { // dev_t st_dev; /* ID of device containing file */ // ino_t st_ino; /* inode number */ // mode_t st_mode; /* protection */ // 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; /* blocksize for filesystem I/O */ // blkcnt_t st_blocks; /* number of 512B blocks allocated */ // // /* 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 // }; // chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out main.c 文件名:main.c 文件大小:1454字节 chunli@ubuntu16:~/linux_c$
access()文件访问函数,测试文件是否存在程序
chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out main.c ./main.c 存在 chunli@ubuntu16:~/linux_c$ chunli@ubuntu16:~/linux_c$ chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include //#include int main(void) { if(access("./main.c",F_OK) < 0) { perror("open ./haha.txt"); exit(1); } printf("./main.c 存在\n"); } // int access(const char *pathname, int mode); // The mode specifies the accessibility check(s) to be performed, // and is either the value F_OK, or a mask consisting of the bitwise // OR of one or more of R_OK, W_OK,and X_OK. F_OK tests for the // existence of the file. R_OK, W_OK, and X_OK test whether the // file exists and grants read, write, and execute permissions, respec‐tively. //RETURN VALUE: // On success (all requested permissions granted, // or mode is F_OK and the file exists), zero is returned. // On error (at least one bit in mode asked for a permission , // that is denied, or mode is F_OK and the file does not exist, // or some other error occurred), -1 is returned, and errno is set appropriately. chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out main.c ./main.c 存在 chunli@ubuntu16:~/linux_c$
黏住位:用户以root权限执行
chunli@ubuntu16:~$ ll /usr/bin/passwd -rwsr-xr-x 1 root root 53K 3月 29 17:25 /usr/bin/passwd*
chmod()函数
chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include //#include int main(int argc,char **argv) { if(argc < 3) { printf("参数不够!\n"); } //需要测试文件是否存在 //"0222" => 转8进制 int mode = atoi(argv[2]); chmod(argv[1],mode); } //需要完善的地方: //1 字符串转8进制 //2 判断文件是否存在才应该去chmod chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out file 111 chunli@ubuntu16:~/linux_c$ ll 总用量 16K -rwxrwxr-x 1 chunli chunli 8.5K 8月 4 09:59 a.out* ---xr-xrwx 1 chunli chunli 0 8月 4 09:55 file* -rw-rw-r-- 1 chunli chunli 435 8月 4 09:59 main.c chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out file 511 chunli@ubuntu16:~/linux_c$ ll 总用量 16K -rwxrwxr-x 1 chunli chunli 8.5K 8月 4 10:00 a.out* -rwxrwxrwx 1 chunli chunli 0 8月 4 09:55 file* -rw-rw-r-- 1 chunli chunli 435 8月 4 09:59 main.c chunli@ubuntu16:~/linux_c$
utime()更新文件时间函数
// #include// #include // // int utime(const char *filename, const struct utimbuf *times); // // #include // // int utimes(const char *filename, const struct timeval times[2]);
truncate()函数,截断文件
// #include// #include // // int truncate(const char *path, off_t length); // int ftruncate(int fd, off_t length);
2.7.1 link
创建一个硬链接
当rm删除文件时,只是删除了目录下的记录项和把inode硬链接计数减1,当硬链接计数
减为0时,才会真正的删除文件。
#include
int link(const char *oldpath, const char *newpath);
* 硬链接通常要求位于同一文件系统中,POSIX允许夸文件系统
* 符号链接没有文件系统限制
* 通常不允许创建目录的硬链接,某些unix系统下超级用户可以创建目录的硬链
* 创建目录项以及增加硬链接计数应当是一个原子操作
2.7.2 symlink
int symlink(const char *oldpath, const char *newpath)
2.7.3 readlink
读符号链接所指向的文件名字,不读文件内容
ssize_t readlink(const char *path, char *buf, size_t bufsiz)
2.7.4 unlink
int unlink(const char *pathname)
1. 如果是符号链接,删除符号链接
2. 如果是硬链接,硬链接数减1,当减为0时,释放数据块和inode
3. 如果文件硬链接数为0,但有进程已打开该文件,并持有文件描述符,则等该进程关闭该文件时,kernel才真正
去删除该文件
4. 利用该特性创建临时文件,先open或creat创建一个文件,马上unlink此文件
rm 底层也是调用unlink函数
2.8 rename
文件重命名
#include
int rename(const char *oldpath, const char *newpath);
2.9 chdir
#include
int chdir(const char *path);
int fchdir(int fd);
改变当前进程的工作目录
2.10 getcwd
获取当前进程的工作目录
#include
char *getcwd(char *buf, size_t size);
chdir(),getcwd() char *getcwd(char *buf, size_t size);//用户自己定义字符数组 char *getwd(char *buf); //没有数组大小检查 char *get_current_dir_name(void);//函数静态数组或者堆空间
获取文件路径
chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include int main(int argc,char **argv) { char buf [10] = {0}; chdir("/home"); getcwd(buf,sizeof(buf)); printf("%s \n",buf); } chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out file 511 /home chunli@ubuntu16:~/linux_c$
pathconf 文件配置信息
#include
long fpathconf(int fd, int name);
long pathconf(char *path, int name);
chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include int main(int argc,char **argv) { printf("%ld\n",fpathconf(STDOUT_FILENO,_PC_NAME_MAX)); printf("%ld\n",pathconf("./main.c",_PC_NAME_MAX)); return 0; } chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out file 511 255 255 chunli@ubuntu16:~/linux_c$
opendir() readdir() 目录遍历
struct dirent struct stat chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include #define MAX_PATH 1024 /* dirwalk: apply fcn to all files in dir */ void dirwalk(char *dir, void (*fcn)(char *)) //遍历目录 { char name[MAX_PATH]; struct dirent *dp; DIR *dfd; if ((dfd = opendir(dir)) == NULL) //如果打开目录失败 { fprintf(stderr, "dirwalk: can't open %s\n", dir); return; } while ((dp = readdir(dfd)) != NULL) //读取目录内容 { if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) { continue; /* skip self and parent */ } if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))// 杠与0"/home/chunli\0" { fprintf(stderr, "dirwalk: name %s %s too long\n",dir, dp->d_name); } else { sprintf(name, "%s/%s", dir, dp->d_name); (*fcn)(name); } } closedir(dfd); } /* fsize: print the size and name of file "name" */ void fsize(char *name) //显示文件的大小 { struct stat stbuf; if (stat(name, &stbuf) == -1) { fprintf(stderr, "fsize: can't access %s\n", name); return; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) //判断是不是目录 { dirwalk(name, fsize); //如果是目录就递归 } printf("%8ld字节 %s\n", stbuf.st_size, name); } int main(int argc, char **argv) { if (argc == 1) /* default: current directory */ { fsize("."); } else { while (--argc > 0) //这样做,可以把程序后面的参数全部遍历 { fsize(*(++argv)); } } return 0; } chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out ../linux_c/ 0字节 ../linux_c//file 1504字节 ../linux_c//main.c 12288字节 ../linux_c//.main.c.swp 9232字节 ../linux_c//a.out 4096字节 ../linux_c/ chunli@ubuntu16:~/linux_c$
dup/dup2
#include
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup和dup2都可用来复制一个现存的文件描述符,使两个文件描述符指向同一个file结
构体。如果两个文件描述符指向同一个file结构体,File Status Flag和读写位置只保存一
份在file结构体中,并且file结构体的引用计数是2。如果两次open同一文件得到两个文件
描述符,则每个描述符对应一个不同的file结构体,可以有不同的File Status Flag和读写
位置。请注意区分这两种情况。
chunli@ubuntu16:~/linux_c$ cat main.c #include#include #include #include #include #include int main(void) { int fd, save_fd; char msg[] = "This is a test\n"; fd = open("somefile", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if(fd<0) { perror("open"); exit(1); } printf("fd = %d\n",fd); save_fd = dup(STDOUT_FILENO); printf("save_fd = %d\n",save_fd); dup2(fd, STDOUT_FILENO); //这个步骤会关闭STDOUT_FILENO, fd就是标准输出了 printf("第3次 fd = %d\n",fd); close(fd); write(STDOUT_FILENO, msg, strlen(msg)); dup2(save_fd, STDOUT_FILENO); write(STDOUT_FILENO, msg, strlen(msg)); close(save_fd); return 0; } chunli@ubuntu16:~/linux_c$ gcc main.c && ./a.out fd = 3 save_fd = 4 This is a test chunli@ubuntu16:~/linux_c$ cat somefile 第3次 fd = 3 This is a test chunli@ubuntu16:~/linux_c$
2.14 练习
1. 实现ls -l功能,可以解析文件权限位。
2. 实现ls -l功能,可以解析出文件所有者和文件所有组。(偏难)
3. 实现rm删除命令,如
rm file
rm directory
*注意,千万不要在你有代码的目录下做测试,防止删除你的有用文件,友情提示(rmdir/unlink和递归遍历目
录)
4. 从文件里面读出1000个随机数,进行排序,再写到另一文件中。(考虑使用重定向dup/dup2)