代码: https://github.com/WHaoL/study/tree/master/00_06_Linux_SystemCode_and_SocketCode
代码: https://gitee.com/liangwenhao/study/tree/master/00_06_Linux_SystemCode_and_SocketCode
1. 文件IO
1.1 Linux系统IO和C标准库IO
1.标准C库IO函数
fopen -> open
// linux c FILE结构体定义: /usr/include/libio.h
struct _IO_FILE
{
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
// 在文件: /usr/include/stdio.h
typedef struct _IO_FILE FILE;
2.标准C 库IO和 Linux系统IO的关系
/*
1. 使用标准c函数往磁盘写数据:
- 数据进入到函数的缓冲区
- 缓冲区满了, 写入磁盘
- 强制这些数据写入磁盘, flush/fclose, 等
- 标准c函数会调用Linux系统函数
- 数据由linux系统函数写入到磁盘
1. 读磁盘
- 标准C函数调用系统函数读磁盘数据
- Linux系统函数将读到的数据写入标准C函数的缓冲区
- 标准C函数去缓冲区中读数据
*/
1.2 虚拟地址空间
// 每启动一个磁盘应用程序(进程), 这个程序就对应一个自己的虚拟地址空间
// 虚拟地址空间:
// 1. 用户区
// .text -> 代码区
// .data .bss -> 全局数据区
// 黄色区域 -> 堆区(比栈大得多)
// 橙色 -> 栈区(比较小)
1. 内核区
- 只有内核可以操作其中的数据, 用户是不能读写的
- 1G
- 内核区用于进程管理的部分 -> 进程控制块(结构体)
在进程控制块中有一个组成部分 -> 文件描述符表(整形数组)
- 这个数组默认大小: 1024, 代表在当前应用程序中(进程), 能够同时打开的文件个数
/*
标准c中的三个FILE*, 对应的是终端
标准输入: stdin -> 文件描述符: STDIN_FILENO(0) -> 当前终端对应的文件
标准输出: stdout -> 文件描述符: STDOUT_FILENO(1) -> 当前终端对应的文件
标准错误: stderr -> 文件描述符: STDERR_FILENO(2) -> 当前终端对应的文件
*/
int buf[1024];
如果打开对应的某个磁盘文件, 这个文件对应一个文件描述符, 这个文件描述符被存储到文件描述符表中
- 默认文件描述表数组所有的元素都是空的, 然后前三个被终端占用了, 分别赋值为0, 1, 2
- 未占用的元素应该是空的, 没有存储数据的元素
- 找到之后如何赋值: 是第几个元素就被赋值为几
1.3 Linux系统IO函数
perror
// 查看错误号:
// /usr/include/asm-generic/errno-base.h
// /usr/include/asm-generic/errno.h
// errno: Linux系统函数库中的全局变量, 记录函数调用失败之后的错误号, 每个错误号都有对应的错误描述
// 通过错误号得到错误描述
// 参数: 用户对错误信息的描述, 调用这个函数错误信息会被打印到终端
// 用户描述+系统对错误编号的描述
#include <stdio.h>
void perror(const char *s);
open/close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 打开一个已经存在的文件
int open(const char *pathname, int flags);
// 创建新文件
int open(const char *pathname, int flags, mode_t mode);
参数:
- pathname: 要操作的文件的文件名
- flags: 对文件的操作权限
必选项: O_RDONLY, O_WRONLY, or O_RDWR, 不能同时用, 只能用一个
可选项:
- O_APPEND: 追加, 指定文件文件有写权限的时候可追加
- O_CREAT: 文件存在不创建, 不存在就创建
- O_EXCL: 检测文件是否存在, 必须要和O_CREAT一起使用
O_CREAT | O_EXCL
- mode: 8进制整形数, 0777, 创建出的新文件的权限
- 实际权限的算法: (mode & ~umask)
- 假设: 权限: 0664, umask: 0002, ~umask: 775
110 110 100
111 111 101
&
110 110 100
返回值:
- 成功: 可用文件描述符
- 失败: -1
#include <unistd.h>
int close(int fd);
参数:
fd: open成功得到的文件描述符
// 示例程序
// 检测文件是否存在
// 不存在, 创建新文件, 存在返回-1
int fd2 = open("./world.txt", O_RDWR|O_CREAT|O_EXCL, 0777);
printf("fd2 = %d\n", fd2);
if(fd2 == -1)
{
perror("open-world.txt");
}
read
// 标准C库, 有缓冲区, 默认8M
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
// Linux系统函数没有缓冲区
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
- fd: open文件之后得到的文件描述符, 通过该fd可用找到磁盘文件
- buf: 存储数据的缓冲区地址(数组地址)
- count: 缓冲区大小(数组最大容量)
返回值:
- 成功: 读到的字节数
- 文件读完了: 返回0
- 失败: -1
write
// 标准C库, 有缓冲区, 默认8k
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
// Linux系统函数没有缓冲区
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
- fd: open文件之后得到的文件描述符, 通过该fd可用找到磁盘文件
- buf: 存储了要写的数据
- count: buf中存储的有效数据的长度
返回值:
- 成功: 写入的字节数
- 什么也没写: 0
- 失败: -1
// 准备一个比较大的磁盘文件, open两个文件, 一个读文件, 一个读到的数据写入另一个文件中
lseek
// fseek
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
// lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
- fd: open文件之后得到的文件描述符, 通过该fd可用找到磁盘文件
- offset: 一个整形的偏移量
- whence:
SEEK_SET: 设置文件指针偏移量, 偏移量就是通过第二个参数指定的//从文件头开始偏移
SEEK_CUR: 当前文件指针偏移量 + 第二个参数指定的偏移//从当前指针位置开始偏移
EEK_END: 当前文件大小 + 第二个参数指定的偏移//从文件尾开始偏移
返回值: 文件指针最后的偏移值
// 1. 文件指针移动到文件头(重置文件指针)
lseek(fd, 0, SEEK_SET);
// 1. 获取当前文件指针的位置
lseek(fd, 0, SEEK_CUR);
// 2. 获取文件总大小
lseek(fd, 0, SEEK_END);
// 4. 可以拓展文件大小, 原文件大小100字节, 拓展大小为110, 多出的字节是10
// 使用lseek拓展文件大小, 最后必须进行一次写操作, 才能成功
lseek(fd, 10, SEEK_END);
write(fd, " ", 1);
2. Linux其他系统函数
1.stat/lstat函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
参数:
- pathname: 操作的文件的路径
- buf: 结构体变量, 传出
// man fstat
// 摘自man手册 fstat()
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; /* 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
};
struct stat
{
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限, 16位整形数
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
// 摘自man手册 fstat()
// st_mode的各个标志位
The following mask values are defined for the file mode component of the st_mode field:
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
关于变量 st_mode:
- st_mode -- 16位整数
○ 0-2 bit -- 其他人权限
- S_IROTH 00004 读权限
- S_IWOTH 00002 写权限
- S_IXOTH 00001 执行权限
- S_IRWXO 00007 掩码, 过滤 st_mode中除其他人权限以外的信息
○ 3-5 bit -- 所属组权限
- S_IRGRP 00040 读权限
- S_IWGRP 00020 写权限
- S_IXGRP 00010 执行权限
- S_IRWXG 00070 掩码, 过滤 st_mode中除所属组权限以外的信息
○ 6-8 bit -- 文件所有者权限
- S_IRUSR 00400 读权限
- S_IWUSR 00200 写权限
- S_IXUSR 00100 执行权限
- S_IRWXU 00700 掩码, 过滤 st_mode中除文件所有者权限以外的信息
○ 12-15 bit -- 文件类型
- S_IFSOCK 0140000 套接字
- S_IFLNK 0120000 符号链接(软链接)
- S_IFREG 0100000 普通文件
- S_IFBLK 0060000 块设备
- S_IFDIR 0040000 目录
- S_IFCHR 0020000 字符设备
- S_IFIFO 0010000 管道
- S_IFMT 0170000 掩码,过滤 st_mode中除文件类型以外的信息
S_IFMT 0170000 bit mask for the file type bit field
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
// 判断文件所有者对文件有没有执行权限
if(S_IXUSR & stat.st_mode)
{
}
if((stat.st_mode & S_IFMT) == S_IFREG)
{
}
// 调用
struct stat st;
stat(filePathName, &st);
if (S_ISREG(st.st_mode))
{
/* Handle regular file */
}
// 判断文件类型的宏 m == 结构体中的变量st_mode
S_ISREG(st.st_mode) is it a regular file?
S_ISDIR(st.st_mode) directory?
S_ISCHR(st.st_mode) character device?
S_ISBLK(st.st_mode) block device?
S_ISFIFO(st.st_mode) FIFO (named pipe)?
S_ISLNK(st.st_mode) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(st.st_mode) socket? (Not in POSIX.1-1996.)
man文档的stat()示例1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct stat buffer;
int status;
...
status = stat("/home/cnd/mod1", &buffer);
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
#include <stdint.h>
struct dirent *dp;
struct stat statbuf;
struct passwd *pwd;
struct group *grp;
struct tm *tm;
char datestring[256];
//...
/* Loop through directory entries. */
while ((dp = readdir(dir)) != NULL)
{
/* Get entry's information. */
if (stat(dp->d_name, &statbuf) == -1)
continue;
/* Print out type, permissions, and number of links. */
printf("%10.10s", sperm(statbuf.st_mode));
printf("%4d", statbuf.st_nlink);
/* Print out owner's name if it is found using getpwuid(). */
if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
printf(" %-8.8s", pwd->pw_name);
else
printf(" %-8d", statbuf.st_uid);
/* Print out group name if it is found using getgrgid(). */
if ((grp = getgrgid(statbuf.st_gid)) != NULL)
printf(" %-8.8s", grp->gr_name);
else
printf(" %-8d", statbuf.st_gid);
/* Print size of file. */
printf(" %9jd", (intmax_t)statbuf.st_size);
tm = localtime(&statbuf.st_mtime);
/* Get localized date string. */
strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), tm);
printf(" %s %s\n", datestring, dp->d_name);
}
man文档的fstat()示例2
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysmacros.h>
int main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1)
{
perror("stat");
exit(EXIT_FAILURE);
}
// st_dev This field describes the device on which this file resides.
// (The major(3) and minor(3) macros may be useful to decompose the device ID in this field.)
printf("ID of containing device: [%lx,%lx]\n",
(long)major(sb.st_dev), (long)minor(sb.st_dev));
printf("File type: ");
switch (sb.st_mode & S_IFMT)
{
case S_IFBLK:
printf("block device\n");
break;
case S_IFCHR:
printf("character device\n");
break;
case S_IFDIR:
printf("directory\n");
break;
case S_IFIFO:
printf("FIFO/pipe\n");
break;
case S_IFLNK:
printf("symlink\n");
break;
case S_IFREG:
printf("regular file\n");
break;
case S_IFSOCK:
printf("socket\n");
break;
default:
printf("unknown?\n");
break;
}
printf("I-node number: %ld\n", (long)sb.st_ino);
printf("Mode: %lo (octal)\n",
(unsigned long)sb.st_mode);
printf("Link count: %ld\n", (long)sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n",
(long)sb.st_uid, (long)sb.st_gid);
printf("Preferred I/O block size: %ld bytes\n",
(long)sb.st_blksize);
printf("File size: %lld bytes\n",
(long long)sb.st_size);
printf("Blocks allocated: %lld\n",
(long long)sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
exit(EXIT_SUCCESS);
}
// [root@lwh test]# ./execute test2.cpp
// ID of containing device: [fd,0]
// File type: regular file
// I-node number: 53108702
// Mode: 100644 (octal)
// Link count: 1
// Ownership: UID=0 GID=0
// Preferred I/O block size: 4096 bytes
// File size: 1931 bytes
// Blocks allocated: 8
// Last status change: Sun Jul 19 12:20:06 2020
// Last file access: Sun Jul 19 12:20:16 2020
// Last file modification: Sun Jul 19 12:20:06 2020
// [root@lwh test]#
stat() Demo
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])// a.out fileName
{
if(argc < 2)
{
printf("a.out filename\n");
exit(1);
}
struct stat buf_st;
int ret = lstat(argv[1], &buf_st);
if(ret == -1)
{
perror("stat");
exit(1);
}
printf("file size = %d\n", (int)buf_st.st_size);
return 0;
}
2.文件属性函数
1.access()
int access(const char *pathname, int mode);
// 判断文件权限, 或者文件是否存在
int access(const char *pathname, int mode);
参数:
- pathname: 文件名
- mode:
R_OK: 判断文件是不是有读权限
W_OK: 判断文件是不是有写权限
X_OK: 判断文件是不是有执行权限
F_OK: 判断当前文件是否存在
返回值:
判断成功: 0,
失败: -1
文件有判断的权限:0
文件没有判断的权限:-1
access() Demo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("%s argv err \n", argv[0]);
exit(1);
}
int ret = 0;
ret = access(argv[1], W_OK);
if (ret == -1)
{
perror("access");
exit(1);
}
if (ret == 0)
{
printf("you can write this file.\n");
}
return 0;
}
2.chmod() chown()
int chmod(const char *filename, int mode);
// 修改文件权限
// chmod 0777 a.txt
int chmod(const char *filename, int mode);
参数:
- filename: 要修改文件权限的文件的名字
- mod: 八进制数
int chown(const char *path, uid_t owner, gid_t group);
// 修改文件所有者
int chown(const char *path, uid_t owner, gid_t group);
参数:
- path: 要修改的文件名
- owner: 用户ID, stat /etc/passwd
- group: 组ID /etc/group
chmod() chown() Demo
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) // a.out filename mod
{
if (argc < 3)
{
printf("%s argv err \n", argv[0]);
exit(1);
}
int mode = strtol(argv[2], NULL, 8);
int ret = chmod(argv[1], mode);
if (ret == -1)
{
perror("chmod");
exit(1);
}
ret = chown(argv[1], 1001, 1002);
if (ret == -1)
{
perror("chown");
exit(1);
}
return 0;
}
3.truncate()
int truncate(const char *path, off_t length);
// 修改文件大小
int truncate(const char *path, off_t length);
参数:
- path: 要操作的文件
- length: 最终的文件大小
- length > 源文件大小 ==> 文件拓展, 添加字符0
- length < 源文件大小 ==> 文件被裁剪, 尾部的被删除
truncate() Demo
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[]) // a.out truncateFileName length
{
if (argc < 3)
{
printf("a.out filename size\n");
exit(1);
}
long int len = strtol(argv[2], NULL, 10);
int aa = truncate(argv[1], len);
if (aa == -1)
{
perror("truncate");
exit(1);
}
return 0;
}
strtol()
long int strtol(const char *str, char **endptr, int base)
//参数
// str -- 要转换为长整数的字符串。
// endptr -- 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
// base -- 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0。
//功能说明
// 把str中的数字提取到返回值中
// 把str中数字之后的字符串提取到endptr中
// base代表了进制
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("./a.out number: ");
exit(1);
}
char *pt;
int number = strtol(argv[1], &pt, 16);
printf("number = %x\n", number);
printf("pt = %s\n", pt);
return 0;
}
// [root@lwh test]# ./execute 16834Helloworld
// number = 16834
// pt = Helloworld
// [root@lwh test]#
ls -l fileName 的C实现
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("./a.out filename\n");
exit(1);
}
struct stat st;
int ret = stat(argv[1], &st);
if (ret == -1)
{
perror("stat");
exit(1);
}
// 存储文件类型和访问权限
char perms[11] = {
0};
// 判断文件类型
switch (st.st_mode & S_IFMT)
{
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFREG:
perms[0] = '-';
break;
case S_IFBLK:
perms[0] = 'b';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFSOCK:
perms[0] = 's';
break;
case S_IFIFO:
perms[0] = 'p';
break;
default:
perms[0] = '?';
break;
}
// 判断文件的访问权限
// 文件所有者
perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
// 文件所属组
perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
// 其他人
perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
// 硬链接计数
int linkNum = st.st_nlink;
// 文件所有者
char *fileUser = getpwuid(st.st_uid)->pw_name;
// 文件所属组
char *fileGrp = getgrgid(st.st_gid)->gr_name;
// 文件大小
int fileSize = (int)st.st_size;
// 修改时间
char *time = ctime(&st.st_mtime);
char mtime[512] = {
0};
strncpy(mtime, time, strlen(time) - 1);
char buf[1024];
sprintf(buf, "%s %d %s %s %d %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
printf("%s\n", buf);
return 0;
}
3.目录操作函数
1.rename()
int rename(const char *oldpath, const char *newpath);
// 文件重命名
int rename(const char *oldpath, const char *newpath);
参数:
- oldpath: 旧的文件名
- newpath: 新的文件名
rename() Demo
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) // a.out fileName NewFileName
{
if (argc < 3)
{
printf("a.out oldName newName\n");
exit(1);
}
int ret = rename(argv[1], argv[2]);
if (ret == -1)
{
perror("rename");
exit(1);
}
return 0;
}
2.chdir() getcwd()
int chdir(const char *path);
// 修改进程的工作目录
// 在 /home/itcat启动a.out, a.out的工作目录 /home/itcast
// chdir("/") -> 进程切换到了根目录
int chdir(const char *path);
char *getcwd(char *buf, size_t size);
// == pwd命令
char *getcwd(char *buf, size_t size);
// 参数:
// - buf: 存储路径, 指向一个由内存大小的数组
// - size: 修饰buf大小
// 返回值:
// 指针指向一块内存, 这个内存就是第一个参数
chdir() getcwd() Demo
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("a.out dir: \n");
exit(1);
}
int ret = chdir(argv[1]);
if (ret == -1)
{
perror("chdir");
exit(1);
}
int fd = open("chdir.txt", O_CREAT | O_RDWR, 0777);
if (fd == -1)
{
perror("open");
exit(1);
}
close(fd);
char buf[128];
getcwd(buf, sizeof(buf));
printf("current dir: %s\n", buf);
return 0;
}
[root@lwh test]# ./execute /home/lwh/Desktop/study/test/testshell/
current dir: /home/lwh/Desktop/study/test/testshell
[root@lwh test]#
3.mkdir()
int mkdir(const char *pathname, mode_t mode);
// 创建目录
// 如果创建目录, 这个目录必须要有执行权限
int mkdir(const char *pathname, mode_t mode);
参数:
- pathname: 目录名
- mode: 目录的权限 mode & ~umask
mkdir() Demo
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
if (argc < 3)
{
printf("a.out newDir mode\n");
exit(1);
}
int mode = strtol(argv[2], NULL, 8);
int ret = mkdir(argv[1], mode);
if (ret == -1)
{
perror("mkdir");
exit(1);
}
return 0;
}
4.rmdir()
int rmdir(const char *pathname);
// == rmdir命令, 只能删除空目录 rm -r
int rmdir(const char *pathname);
5.自动清除缓存文件
// 删除磁盘文件
// 应用场景举例:自动清除缓存
#include <unistd.h>
int unlink(const char *pathname);
int fd = open("hello.txt", o_rdwr);//举例:假如: 有一个文件hello.txt
unlink("hello.txt");// 这个时候无法删除;当文件被close的时候, 文件才被删除
......;
.......;
close(fd);// 文件才被删除
6.目录遍历函数
1.opendir()
// 打开目录
DIR *opendir(const char *name);
参数:
- name: 要打开的目录
返回值:
成功: 有效指针, 失败: NULL
opendir() Demo
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("a.out path\n");
exit(1);
}
DIR *dir = opendir(argv[1]);
if (dir == NULL)
{
perror("opendir");
exit(1);
}
char buf[512];
getcwd(buf, sizeof(buf));
printf("current dir: %s\n", buf);
closedir(dir);
return 0;
}
2.readdir()
// 读目录, 参数opendir的返回值
// 因为一个目录中还有目录, 读目录是递归操作
// 读当前目录: 文件是有若干个的, 调用一次readdir只能读一个文件信息, 读所有while()
struct dirent *readdir(DIR *dirp);
// 返回一个结构体, 这个对应一个文件
struct dirent
{
ino_t d_ino; // 此目录进入点的inode
ff_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_name 所指的文件类型
har d_name[256]; // 文件名
};
d_type
DT_BLK - 块设备
DT_CHR - 字符设备
DT_DIR - 目录
DT_LNK - 软连接
DT_FIFO - 管道
DT_REG - 普通文件
DT_SOCK - 套接字
DT_UNKNOWN - 未知
3.closedir()
// 关闭目录, 参数就是opendir的返回值
int closedir(DIR *dirp);
读某个目录下普通文件的个数
// 读某个目录下普通文件的个数
// 需要用到递归, 想明白递归结束的条件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
int get_file_num(char *curPath)
{
int total = 0;
DIR *dir = NULL;
// 打开目录
// 循环从目录中读文件
dir = opendir(curPath);
if (dir == NULL)
{
perror("opendir");
return 0;
}
// 存储下一级目录(绝对路径)
char path[1024] = {
0}; //
// 定义readdir()返回的结构体指针
// 通过该指针,可得到文件的文件名
struct dirent *ptr = NULL;
while ((ptr = readdir(dir)) != NULL)
{
// 跳过目录. 和 目录..
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
{
continue;
}
// 是目录的话,递归读取
if (ptr->d_type == DT_DIR)
{
// 拼接下一级目录(绝对路径)
sprintf(path, "%s/%s", curPath, ptr->d_name);
// 递归读目录
total += get_file_num(path);
}
// 如果是普通文件
if (ptr->d_type == DT_REG)
{
total++;
}
}
closedir(dir);
return total;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("./a.out path");
exit(1);
}
int total = get_file_num(argv[1]);
printf("%s has regfile number: %d\n", argv[1], total);
return 0;
}