目录:文件夹
打开目录文件 opendir
找目录下的文件 readdir
关闭目录文件 closedir
opendir 和 readdir 会自动维护当前读到了目录下哪个文件
就像open函数打开文件,文件内容指针在文件头,read函数读一段,文件内容指针自动往后挪一段
每个目录下都有两个默认的文件:
. 当前目录
.. 当前目录的上层目录
mmap: 文件映射虚拟内存
文件读写耗时,io操作也比较耗时,所以直接内存操作,耗时很短
文件映射虚拟内存编程模型:
1.创建或打开文件
2.注意文件大小(写入时要调整文件大小,读时不用管)
3.把文件映射成虚拟内存
4.以 内存操作 方式 操作文件
5.解除映射
6.关闭文件
#include <sys/mman.h> //使用mmap所需头文件
void *mmap(
void *addr, //目的映射地址,填NULL则由操作系统指定
size_t length, //映射长度
int prot, //权限(保护方式)
int flags, //映射方式
int fd, //打开的文件描述符号
off_t offset //文件中映射偏移量(如:从文件第10个字节位置开始映射)填0表示从文件头开始
);
MAP_SHARED MAP_PRIVATE
权限(保护方式)
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
映射方式
MAP_SHARED
MAP_PRIVATE
int munmap(void *addr, size_t length);
相关示例(依旧是大量头文件)
#include <stdio.h>
#include <unistd.h> //linux操作系统标准头文件
#include <string.h> //memcpy
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> //umask
#include <time.h>
#include <sys/time.h>
#include <dirent.h> //遍历目录
#include <fcntl.h> //文件映射虚拟内存
#include <sys/mman.h>
#include <wait.h>
#include <signal.h> //SIGCHLD
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <poll.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <bits/pthreadtypes.h>
#include <aio.h>
// 创建文件夹
void makedir(int argc, char *argv[])
{
if (argc < 2)
{
printf("请输入要创建的目录名\n");
exit(-1);
}
if (2 == argc)
{
printf("创建1个目录:%s\n", argv[1]);
mkdir(argv[1], 0777);
}
else
{
printf("创建%d个目录\n", argc - 1);
for (int i = 1; i < argc; i++)
{
mkdir(argv[i], 0777);
}
}
printf("创建完毕\n");
system("ls");
}
// 遍历目录
void traveldir(int argc, char *argv[])
{
if (argc < 2)
{
printf("请输入要遍历的目录名\n");
exit(-1);
}
DIR *pDir = opendir(argv[1]);
if (NULL == pDir)
{
printf("opendir %s 失败\n", argv[1]);
perror(":");
return;
}
printf("打开目录成功\n");
int num = 0;
struct dirent *pd = NULL;
while (1)
{
pd = readdir(pDir);
if (NULL == pd)
break;
num++;
printf("这是 %s 里第 %d 个文件%s\n", argv[1], num, pd->d_name);
}
printf("遍历完成\n");
closedir(pDir);
}
// 递归遍历目录
void DFS_traveldir(char *pathName)
{
char fileName[256] = {0};
DIR *pDir = opendir(pathName);
if (NULL == pDir)
{
printf("opendir %s 失败\n", pathName);
perror(":");
return;
}
// printf("打开目录成功\n");
int num = 0;
struct dirent *pd = NULL;
while (1)
{
pd = readdir(pDir);
if (NULL == pd)
break;
sprintf(fileName, "%s/%s", pathName, pd->d_name);
if (DT_DIR == pd->d_type)
{
printf("---%d:%s\n", num, fileName);
// 如果是目录就递归调用
if (strcmp(".", pd->d_name) == 0 || strcmp("..", pd->d_name) == 0)
continue;
DFS_traveldir(fileName);
}
else
{
printf("+++%d:%s\n", num, fileName);
}
num++;
// printf("这是 %s 里第 %d 个文件%s\n", argv[1], num, pd->d_name);
}
closedir(pDir);
}
// 文件映射虚拟内存进行读写
struct Student
{
char name[20];
int age;
double score;
} stu = {"张三", 18, 60.1};
void writeFilemmap()
{
int NUM = 1000;
// 1.打开文件
int fd = open("stu.dat", O_RDWR);
if (-1 == fd)
{
// 错误信息会直接通过%m输出出来
printf("打开%s失败:%m\n", "stu.dat");
fd = open("stu.dat", O_WRONLY | O_CREAT, 0666);
if (-1 == fd)
{
printf("创建%s失败:%m\n", "stu.dat");
exit(-1);
}
printf("创建文件成功\n");
}
printf("打开文件成功\n");
// 2.因为是要写入,所以要调整文件大小
int r = ftruncate(fd, NUM * sizeof(stu));
if (-1 == r)
{
printf("调整文件大小失败: %m\n");
close(fd);
return;
}
printf("调整文件大小成功\n");
// 3.文件映射成虚拟内存
struct Student *p = mmap(NULL, NUM * sizeof(stu), PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == p)
{
printf("映射文件失败: %m\n");
close(fd);
return;
}
printf("映射文件成功\n");
struct timeval oldtime, newtime;
gettimeofday(&oldtime, NULL);
// 4.写入
struct Student *pTemp = p;
// 不用write了,直接内存操作
for (int i = 0; i < NUM; i++)
{
memcpy(pTemp, &stu, sizeof(stu));
pTemp++;
}
gettimeofday(&newtime, NULL);
printf("%d %u\n", newtime.tv_sec - oldtime.tv_sec, newtime.tv_usec - oldtime.tv_usec);
// 5.解除映射
munmap(p, NUM * sizeof(stu));
// 6.关闭文件
close(fd);
// 使用映射:0 41ms
// 使用文件io:1 331627ms
}
void readFilemmap()
{
int NUM = 1000;
// 1.打开文件
int fd = open("stu.dat", O_RDONLY);
if (-1 == fd)
{
// 错误信息会直接通过%m输出出来
printf("打开%s失败:%m\n", "stu.dat");
return;
}
printf("打开文件成功\n");
// 2.读,不用调整大小
// 3.文件映射成虚拟内存
struct Student *p = mmap(NULL, NUM * sizeof(stu), PROT_READ, MAP_SHARED, fd, 0);
if (MAP_FAILED == p)
{
printf("映射文件失败: %m\n");
close(fd);
return;
}
printf("映射文件成功\n");
// 4.读
printf("读:%s %d %lf\n", p->name, p->age, p->score);
printf("读:%s %d %lf\n", (p + 1)->name, (p + 1)->age, (p + 1)->score);
// 5.解除映射
munmap(p, NUM * sizeof(stu));
// 6.关闭文件
close(fd);
}
int main(int argc, char *argv[])
{
// makedir(argc, argv);
// traveldir(argc, argv);
/*
if (argc < 2)
{
printf("请输入要遍历的目录名\n");
exit(-1);
}
DFS_traveldir(argv[1]);
printf("遍历完成\n");
*/
// writeFilemmap();
// readFilemmap();
}