Linux从入门到开发实战(C/C++)Day03-目录

点击前往Day04-进程

目录:文件夹

打开目录文件    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();
}

猜你喜欢

转载自blog.csdn.net/qq_55149044/article/details/141003396