【本文谢绝转载,原文来自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() 练习:
stat函数获取文件大小
chunli@ubuntu16:~/linux_c$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
//#include <fcntl.h>
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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
//#include <fcntl.h>
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 <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> //#include <fcntl.h> 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 <sys/types.h>
// #include <utime.h>
//
// int utime(const char *filename, const struct utimbuf *times);
//
// #include <sys/time.h>
//
// int utimes(const char *filename, const struct timeval times[2]);
truncate()函数,截断文件
// #include <unistd.h> // #include <sys/types.h> // // int truncate(const char *path, off_t length); // int ftruncate(int fd, off_t length);
2.7.1 link
创建一个硬链接
当rm删除文件时,只是删除了目录下的记录项和把inode硬链接计数减1,当硬链接计数
减为0时,才会真正的删除文件。
#include <unistd.h>
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 <stdio.h>
int rename(const char *oldpath, const char *newpath);
2.9 chdir
#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd);
改变当前进程的工作目录
2.10 getcwd
获取当前进程的工作目录
#include <unistd.h>
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 <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> 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 <unistd.h>
long fpathconf(int fd, int name);
long pathconf(char *path, int name);
chunli@ubuntu16:~/linux_c$ cat main.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#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 <unistd.h>
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 <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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)
转载于:https://blog.51cto.com/990487026/1834411