【北京迅为】嵌入式学习之Linux系统编程篇 https://www.bilibili.com/video/BV1zV411e7Cy/ 个人学习笔记
文章目录
- mkdir() 函数
- opendir() 和 closedir() 函数
- readdir() 函数
- 综合实验
mkdir() 函数
- 头文件:
#include <sys/types.h>
#include <sys/stat.h>
- 函数定义
int mkdir(const char *pathname, mode_t mode);
pathname 为要创建的目录路径名,mode 用来指定新建文件夹的权限(与文件 IO 的 mode 参数相同),下面是文件 IO 中 mode 参数的介绍:
#define S_IRUSR 00400 /*文件所有者可读*/
#define S_IWUSR 00200 /*文件所有者可写*/
#define S_IXUSR 00100 /*文件所有者可执行*/
#define S_IRGRP 00040 /*与文件所有者同组的用户可读*/
#define S_IWGRP 00020 /*与文件所有者同组的用户可写*/
#define S_IXGRP 00010 /*与文件所有者同组的用户可执行*/
#define S_IROTH 00004 /*与文件所有者不同组的用户可读*/
#define S_IWOTH 00002 /*与文件所有者不同组的用户可写*/
#define S_IXOTH 00001 /*与文件所有者不同组的用户可可执行*/
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) /* 所有用户可读、写、执行 */
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)/* 所有用户可读、写、执行*/
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) /* 所有用户可读 */
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) /* 所有用户可写 */
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) /* 所有用户可执行 */
如果直接填 0644(0不能省略,0644 代表八进制数 644),表示文件所有者可读写,同组用户和其他用户只读。
上面是文件权限的介绍,如要要访问目录,需要加上可执行权限
- 返回值:
创建成功返回 0,失败返回 -1 。
opendir() 和 closedir() 函数
opendir()
- 头文件:
#include <sys/types.h>
#include <dirent.h>
- 函数定义
DIR *opendir(const char *name);
name 为要打开的目录名
- 返回值:
操作成功返回目录的指针,失败返回 NULL。
closedir()
- 头文件:
#include <sys/types.h>
#include <dirent.h>
- 函数定义
int closedir(DIR *dirp);
目录指针 dirp 是 opendir 返回的变量,指向要关闭的目录。
- 返回值:
操作成功返回 0 ,失败返回 -1 。
readdir() 函数
- 头文件:
#include <dirent.h>
- 函数定义
struct dirent *readdir(DIR *dirp);
目录指针 dirp 是 opendir 返回的变量,指向要读取的目录。
- 返回值:
读取目录成功,返回一个静态定义的 struct dirent
变量,如果出错或者读到目录流的末尾,返回 NULL。
struct dirent 结构体定义如下:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
d_type(文件类型)和 d_name(文件名)是我们要用到的成员变量,d_type 的可取值包括:
这些宏在 dirent.h 有声明,我们无需知道它们具体的数值是多少
使用参考:
// 打印目录类型
void print_dir_type(unsigned char d_type)
{
switch (d_type)
{
case DT_DIR: // a directory
printf("directory");
break;
case DT_REG: // a regular file
printf("regular file");
break;
case DT_BLK: // a block device
printf("block device");
break;
case DT_CHR: // a character device
printf("character device");
break;
case DT_FIFO: // a named pipe (FIFO)
printf("named pipe (FIFO)");
break;
case DT_LNK: // a symbolic link
printf("symbolic link");
break;
case DT_SOCK: // a UNIX domain socket
printf("UNIX domain socket");
break;
default: // DT_UNKNOWN - file type unknown
printf("The file type is unknown");
break;
}
}
readdir() 每次只能读到一个文件的信息,所以如果要遍历整个目录,需要用到循环,参考代码如下:
// 调用readdir遍历目录子文件
struct dirent *dir;
while((dir = readdir(dp)) != NULL)
{
// 打印文件名、文件类型等信息
}
综合实验
打印 A 目录下所有文件名,并拷贝 A 目录下的 a.c 到 B 目录下的 b.c
为了简化代码,这里引入两个库函数:
#include <libgen.h>
char *dirname(char *path); //返回目录名
char *basename(char *path); //返回文件名
注意:使用 dirname(path) 后,path 字符串也会发生变化,所以实际使用时需要提前将 path 备份
在 shell 下面也有对应的命令,
实验代码:
仅供参考
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <libgen.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
char BUFF[1024];
//打印目录类型
void print_dir_type(unsigned char d_type);
//文件拷贝(上一篇笔记代码)
int my_copy(char *src, char *dest);
int main(int argc, char *argv[])
{
int ret;
DIR *dp;
struct dirent *dir;
char src_filename[20];
char dest_filename[20];
if(argc != 3)
{
printf("用法:%s <源文件> <目标文件>.\n", argv[0]);
return -1;
}
// 获取(备份)文件名(路径),两条语句功能类似
sprintf(src_filename, "%s", argv[1]);
strncpy(dest_filename, argv[2], 20);
// 打开源文件目录,之后 argv[1] 变为目录名
dp = opendir(dirname(argv[1]));
if(dp == NULL)
{
printf("目录为空.\n");
return -2;
}
printf("%s 打开成功.\n", argv[1]);
while((dir = readdir(dp)) != NULL)
{
printf("文件名:%-20s", dir->d_name);
printf("\t文件类型:");
print_dir_type(dir->d_type);
printf("\n");
}
// 关闭目录
closedir(dp);
// 创建目标文件的目录,之后 argv[2] 变为目录名
ret = mkdir(dirname(argv[2]), 0755);
if(ret < 0)
{
printf("%s 创建失败.\n", argv[2]);
return -3;
}
printf("%s 创建成功.\n", argv[2]);
// 文件操作(上一篇笔记代码)
my_copy(src_filename, dest_filename);
return 0;
}
// 打印目录类型
void print_dir_type(unsigned char d_type)
{
switch (d_type)
{
case DT_DIR: // a directory
printf("directory");
break;
case DT_REG: // a regular file
printf("regular file");
break;
case DT_BLK: // a block device
printf("block device");
break;
case DT_CHR: // a character device
printf("character device");
break;
case DT_FIFO: // a named pipe (FIFO)
printf("named pipe (FIFO)");
break;
case DT_LNK: // a symbolic link
printf("symbolic link");
break;
case DT_SOCK: // a UNIX domain socket
printf("UNIX domain socket");
break;
default: // DT_UNKNOWN - file type unknown
printf("The file type is unknown");
break;
}
}
//文件拷贝(上一篇笔记代码)
int my_copy(char *src, char *dest)
{
int ret = 0, sum = 0;
int fd1, fd2;
// 打开 src
fd1 = open(src, O_RDONLY);
if(fd1 < 0)
{
printf("%s 打开失败.\n", src);
return -1;
}
// 读取 src 文件大小
ret = lseek(fd1, 0, SEEK_END);
if(ret != 0)
{
printf("%s 大小为 %d bytes.\n", src, ret);
lseek(fd1, 0, SEEK_SET); // 将文件指针指向开头
}
else
{
printf("%s 为空, 操作失败.\n", src);
return -2;
}
// 打开(创建)dest,写入文件采用截断的方式
fd2 = open(dest, O_CREAT|O_TRUNC|O_RDWR, 0644);
if(fd2 < 0)
{
printf(" 打开失败.\n");
return -3;
}
// 将 src 内容拷贝到 dest
while((ret = read(fd1, BUFF, 1024)) != 0)
{
sum += write(fd2, BUFF, ret);
}
printf("成功向 %s 写入 %d bytes.\n", dest, sum);
// 关闭 src 和 dest
close(fd1);
close(fd2);
return 0;
}
程序运行结果:(打印 A 目录下的所有文件,并将 A/a.c 拷贝到 B/b.c)
tips:
- 文件夹已存在的情况下,再使用 mkdir 创建目录,该函数不会返回 0,所以我提前将原来的 B/ 删除,当然,我们也可以根据 mkdir 的错误号来决定下一步如何操作,而不是像上面那样不成功就直接退出程序。
- 创建目录时,需要比普通文件多一个可执行权限,否则无法进入目录。