马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
前言:
在构建 boost 库站内搜刮引擎时,Parser 模块是数据处置惩罚的焦点环节,它的焦点功能包罗:
- 筛选出全部 .html 文件,为后续分析提供数据源;
- 从 .html 文件中提取 title、content ,并构造对应官网的 url 所在;
- 将洗濯后的数据按自界说格式存储为文本文件,便于后续创建索引。
本文重要解说编写 Parser 模块过程中涉及的部分知识。
1. EnumFile() 方法
EnumFile() 方法的功能是,递归遍历指定目次及其子目次,网络全部后缀为 .html 的平凡文件路径,并将结果存储到传入的 std::vector<std::string> 中。
1.1 boost::filesystem 简介
boost::filesystem 是 Boost 库中的一个组件,用于跨平台处置惩罚文件体系路径、文件使用和目次管理。它提供了面向对象的接口,简化了文件和目次的创建、删除、遍历等使用。
使用:
- 包罗头文件:#include <boost/filesystem>
- 链接 Boost 库:-lboost_system -lboost_filesystem
1.2 焦点类及其使用
1.2.1 path
boost::filesystem::path 用于体现文件体系路径(如文件或目次的路径),提供了跨平台的路径使用本事。
在 Windows 平台,D:\Develop\条记\Boost库搜刮引擎开辟 可以被正确分析。
在 Linux 平台,/home/ZhengTongren/boost-search/data/input 可以被正确分析。
path 可以通过 std::string、const char* 或别的 path 对象举行构造。- const std::string src_path = "data/input/";
- boost::filesystem::path root_path(src_path);
复制代码 干系方法:
- filesystem::exists(path) :查抄路径是否存在
- is_regular_file(path) :判断是否为平凡文件
- path.extension() :获取拓展名,带 . ,如 .html
1.2.2 recursive_directory_iterator
recursive adj. 递归的
boost::filesystem 中,directory_iterator 和 recursive_directory_iterator 的作用雷同于一个 “指针”,用于遍历文件体系中的目次内容。
directory_iterator 提供了一种方式来迭代一个指定目次的内容,但它不会递归进入子目次。
recursive_directory_iterator 则提供了递归遍历目次的功能,它不光会列出指定目次下的全部条目,还会进入每个子目次继续遍历,直到遍历完备个目次树。- boost::filesystem::recursive_directory_iterator it(root_path);
- // root_path 是一个 filesystem::path 类对象;
- // 创建一个递归迭代器,指向 root_path 目录中的第一个条目(文件或子目录);
- // 如果 root_path 不存在或无法访问,则抛出 filesystem_error 异常
- boost::filesystem::recursive_directory_iterator end;
- // 默认构造的迭代器表示结束
- for (; it != end; ++it) { }
- // 通过循环逐个访问条目,直到等于 end
复制代码 1.3 递归遍历、搜集全部 .html 文件路径
- #include <iostream>
- #include <string>
- #include <vector>
- #include <boost/filesystem>
- const std::string src_path = "data/input/";
- bool EnumFile(const std::string& src_path, std::vector<std::string>* files_list)
- {
- namespace fs = boost::filesystem;
- // 1. 初始化 path
- fs::path root_path(src_path);
- // 2. 检查路径是否存在 -- 不存在则 return false
- if (!fs::exists(root_path))
- {
- std::cerr << src_path << " not exits!" << std::endl;
- return false;
- }
- // 3. 递归遍历目录及其子目录文件
- fs::recursive_directory_iterator end;
- for (fs::recursive_directory_iterator it(root_path); it != end; ++it)
- {
- // 3.1 跳过目录文件
- if (!is_regular_file(*it)) continue;
- // 3.2 跳过非 .html 普通文件
- if (it->path().extension() != ".html") continue;
- // 3.3 插入
- files_list->push_back(it->path().c_str());
- }
- return true;
- }
复制代码 2. 文件流使用与 getline
2.1 C++ 文件流类
C++ 中的文件流使用通过 <fstream> 头文件提供的类(如 ifstream、ofstream、fstream)实现,支持对文件的读写使用。
ifstream 用于从文件中读取数据;ofstream 用于将数据写入文件;fstream 支持同时读写文件。
打开模式:
- std::ios::in :以输入模式打开文件
- std::ios:
ut :以输出模式打开文件(覆盖模式)
- std::ios::app :以追加模式打开文件
- std::ios::binary :以二进制模式打开文件
文件的读写模式必须保持划一,以默认模式写入则以默认模式读取,以二进制模式写入则以二进制模式读取。
对于二进制文件,数据直接按其原始字节序列被读取或写入,没有任何表明或转换,这对于处置惩罚图像、音频、视频等非文本数据尤为告急。- // 通用写入函数(二进制)
- bool WriteFile(const std::string& path, const std::string& content)
- {
- std::ofstream out(path, std::ios::out | std::ios::binary);
- if (!out.is_open()) return false;
-
- out << content;
- return true;
- }
- // 通用读取函数(二进制)
- bool ReadFile(const std::string& path, std::string* out)
- {
- std::ifstream in(path, std::ios::in | std::ios::binary);
- if (!in.is_open()) return false;
-
- std::string line;
- while (getline(in, line))
- {
- // ...
- }
- return true;
- }
复制代码 C++ 的文件流类(如 ifstream、ofstream)依照 RAII 原则:
- 资源与对象生命周期绑定:文件流对象在构造时打开文件,在析构时自动调用 close() ;
- 无需手动干预:当流对象离开作用域(即生命周期竣事),析构函数会确保文件正确关闭。
因此,通例环境下可以不显式调用 close() 方法。
在长时间运行的步伐中,若须要提前关闭不再使用的文件、立即开释资源,可以显式调用 close() 。
2.2 getline 函数
getline 函数用于从输入流中按行读取字符串,它会读取直到遇到换行符 \n 为止,并将此换行符从输入流中提取掉(但 \n 不会包罗在返回的字符串中)。
常见用法:
- std::string line;
- getline(std::cin, line);
复制代码- std::ifstream in(path, std::ios::in);
- if (!in.is_open()) return ;
- std::string line;
- while (getline(in, line))
- {
- // ...
- }
- in.close();
复制代码- istream& getline (istream& is, string& str);
- istream& getline (istream& is, string& str, char delim); // 通过 getline 的第三个参数 delim
- char delimiter = ',';
- std::string line;
- getline(std::cin, line, delimiter);
复制代码 2.3 使用 getline vs stringstream
getline 逐行读取,得当处置惩罚大文件,或须要对每一行举行特定处置惩罚的环境。
stringstream 一次性读取整个文件到内存中,得当小文件处置惩罚场景;对于较大的文件,这种方法大概导致内存溢出。
|