一种在C++中读取TXT配置文件的简单方法
A simple way to read TXT config files in C++
这个问题似乎已经被问过了,但我没有为我的案例找到任何方便的解决方案。我有以下TXT配置文件要在C++中读取:
--CONFIGURATION 1 BEGIN--
IP address: 192.168.1.145
Total track length [m]: 1000
Output rate [1/s]: 10
Time [s]: 1
Running mode (0=OFF 1=ON): 1
Total number of attempts: 10
Mode (0=OFF, 1=BEG, 2=ADV, 3=PROF): 1
--Available only for Administrators--
Variable 1 [mV]: 2600
Gain 1 [mV]: 200
Position tracking (0=OFF 1=ON): 0
Coefficient 2 [V]: 5.2
--CONFIGURATION 1 END--
--CONFIGURATION 2 BEGIN--
Max track distance [m]: 10000
Internal track length [m]: 100
Offset distance [mV]: 1180
GAIN bias [mV]: 200
Number of track samples: 1000
Resolution (1 or 2) [profile]: 1
--CONFIGURATION 2 END--
我只需要在每一行的末尾存储值,该值可以是字符串(在IP地址的情况下(、int、float或结构内部的bool。在C中有一个非常简单的解决方案,我使用如下表达式读取每一行:
if(!fscanf(fp, "%*s %*s %*s %*s %dn", &(settings->trackLength))) {
printf("Invalid formatting of configuration file. Check trackLength.n");
return -1;
}
%*s允许丢弃行的标签和感兴趣值之前的空格。我用fgets跳过空行或标题。这种方法也适用于C++。让我的代码保持原样好吗?或者你认为在C++中有更好、简单的方法可以做到这一点吗?非常感谢。
同样在C++中,分割一行很容易。我已经在SO上提供了几个关于如何拆分字符串的答案。不管怎样,我会在这里详细解释,并为您的特殊情况。稍后我还会提供一个完整的工作示例。
我们使用std::getline
的基本功能,它可以读取一整行或一个给定字符的行。请看这里。
让我们举一个例子。如果文本存储在std::string
中,我们将首先将其放入std::istringstream
中。然后我们可以使用std::getline
从std::istringstream
中提取数据。这始终是标准方法。首先,使用std::getline
从文件中读取完整的一行,然后再次将其放入std::istringstream
中,以便能够使用std::getline
再次提取字符串的部分。
如果源行看起来像这样:
Time [s]: 1
我们可以假设我们有几个部分:
- 一个标识符";时间[s]">
- 用作分隔符的冒号
- 一个或多个空间,以及
- 值";1〃
所以,我们可以写这样的东西:
std::string line{}; // Here we will store a complete line read from the source file
std::getline(configFileStream, line); // Read a complete line from the source file
std::istringstream iss{ line }; // Put line into a istringstream for further extraction
std::string id{}; // Here we will store the target value "id"
std::string value{}; // Here we will store the target "value"
std::getline(iss, id, ':'); // Read the ID, get read of the colon
iss >> std::ws; // Skip all white spaces
std::getline(iss, value); // Finally read the value
所以,这是大量的文本。您可能听说过可以链接IO操作,如std::cout << a << b << c
。这是有效的,因为<lt;操作总是返回对给定流的引用。CCD_ 10也是如此。因为它做到了这一点,我们可以使用嵌套语句。也就是说,我们可以将第二个std::getline
放在这个参数位置(实际上是第一个参数(,它期望std::istream
。因此,如果我们遵循这种方法,那么我们可以编写嵌套语句:
std::getline(std::getline(iss, id, ':') >> std::ws, value);
哎呀,这是怎么回事?让我们从内而外进行分析。首先操作CCD_ 13从CCD_;id";。好的,明白了。记住:std::getline,将返回对给定流的引用。那么,上面的简化语句就是
std::getline(iss >> std::ws, value)
接下来,iss >> std::ws
将被评估,并将导致吞噬所有不必要的空白。你猜怎么着,它会返回对gievn流的引用";iss";。
声明现在看起来像:
std::getline(iss, value)
这将读取值。易于理解的
但是,我们还没有结束。当然std::getline将再次返回"iss";。在下面的代码中,你会看到类似的东西
if (std::getline(std::getline(iss, id, ':') >> std::ws, value))
其将以CCD_ 16结束。那么,我们使用iss
作为布尔表达式?为什么这样做,它做什么?它起作用,因为如果状态为OK或出现故障,std::stream
的bool operator
将被覆盖并返回。请参阅此处了解解释。始终检查任何IO操作的结果。
最后但同样重要的是,我们需要用初始化器来解释if
语句。你可以在这里阅读。
我能写
if (std::string id{}, value{}; std::getline(std::getline(iss, id, ':') >> std::ws, value)) {
类似于
std::string id{}, value{};
if (std::getline(std::getline(iss, id, ':') >> std::ws, value)) {
但是第一个示例的优点是,定义的变量将仅在if
-语句范围内可见。因此,我们;"范围";变量尽可能窄。
你应该尽量经常这样做。您还应该始终通过将if
应用于流操作来检查IO操作的返回状态,如上所示。
读取所有内容的完整程序将只是几行代码。
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <iomanip>
int main() {
// Open config file and check, if it coul be opened
if (std::ifstream configFileStream{ "r:\config.txt" }; configFileStream) {
// Here we wills tore the resulting config data
std::unordered_map<std::string, std::string> configData;
// Read all lines of the source file
for (std::string line{}; std::getline(configFileStream, line); )
{
// If the line contains a colon, we treat it as valid data
if (if (line.find(':') != std::string::npos)) {
// Split data in line into an id and a value part and save it
std::istringstream iss{ line };
if (std::string id{}, value{}; std::getline(std::getline(iss, id, ':') >> std::ws, value)) {
// Add config data to our map
configData[id] = value;
}
}
}
// Some debug output
for (const auto& [id, value] : configData)
std::cout << "ID: " << std::left << std::setw(35) << id << " Value: " << value << 'n';
}
else std::cerr << "n*** Error: Could not open config file for readingn";
return 0;
}
对于这个例子,我将id和值存储在一个映射中,这样就可以很容易地访问它们。
- 一种在C++中读取TXT配置文件的简单方法
- Arduino从Txt读取整数
- Visual Studio在尝试读取resource.txt文件时崩溃
- 如何从txt文件中读取多个不同长度的数组?
- 在一次迭代中从 txt 文件中读取多行
- 我可以读取静态对象中的文件.txt吗?C++
- 在Cmake构建CmakeList.txt中读取/解析XML文件
- 从.txt文件中读取浮点型数字并在公式中使用它们
- 为什么我无法打开/读取从 Python 调用的 C 扩展名中的 txt 文件?
- 如何使用c ++读取带有非英文字母的*.txt文件?(国际化)
- 如何将变量从 CMakeLists.txt 读取到 cpp 文件
- 尝试从 txt 读取数据
- C++,从 txt 读取到矢量的双倍,读取整个文件时出现问题
- 编写一个C++ pgm 以从文件"input.txt"读取,每当遇到句点时插入换行符并将修改的内容写入"output.txt"
- C++从 txt 读取数字,直到换线(逻辑回归)
- 使用 2D 矢量从 txt 读取文件
- C++从.txt读取浮点值,并将它们放入未知大小的 2D 数组中
- 从文件.txt读取字符串数组并使用它来玩康威的生命游戏
- 从.txt [c++]读取代码
- 从.txt读取int,将其保存到vector,然后保存到输出文件