写入文件,读取时分隔值

Writing to a File, Separating Values when Reading

本文关键字:分隔 读取 文件      更新时间:2023-10-16

我正在尝试自学编程,而我难以理解的一个早期主题是文件 IO。

到目前为止,我知道我可以保存用逗号分隔的数据,以便以后成功读取该数据。执行以下操作:

int x[] = {1,22,333,4444,55555};
std::ofstream FileWriter;
std::string dataName = "One through Five";
for( int i = 0; i < 5; ++i)
{
    FileWriter << x[i] << ',';
}
FileWriter << dataName << std::endl;
FileWriter.close();

这当然很容易,但这似乎很俗气,实际上效率低下。我想知道是否有更好的方法来保存数据,并且在我以后去阅读数据时仍然可以将其分离。

不幸的是,我所做的搜索只产生了以下内容:

std::getline( FileReader, myStringBuffer, ',');

那么我是否可以存储单独的数据点,以便它们可以在读取时区分为单独的数据点,而无需在保存时使用分隔字符?也就是说,不用一些字符或空格分隔数据。

基本的二进制文件 io 实践将做你想要的。读取二进制数据时,您需要知道正在读取的每条数据的大小;了解这一点将推动您的许多设计决策。如果你想读取一个 int 后跟一个字符串,你需要知道一个 int 的大小(通过调用 sizeof(int)很容易找到),这样你就可以从你尝试加载数据的二进制 blob 中"蚕掉"一个 int 的数据,然后在你读取 int 的数据后,你需要知道你的字符串有多大。由于字符串的长度是可变的,你要么需要假设一个标准长度(哎呀!),要么先从已知大小的数据中读取长度,然后将这么多字节读入字符串。因此,数据编写器需要在写出字符串之前写出字符串(或任何其他可变大小的数据类型)的长度,作为已知的数据大小(例如将大小信息写入为无符号的整数)。

有关组织二进制数据以进行读取/写入的巧妙方法,请查看交换文件格式 (IFF)。这是TIFF,RIFF等的基础,并且是设计二进制文件blob的好方法。它基本上将数据存储为"块",其中数据首先写出一个块ID,然后是块的大小(以字节为单位),然后是该块的数据。这样,读取器程序可以检查块 ID,如果它不想/不知道如何处理某种甚至未知类型的数据,它可以跳过以字节为单位的块大小并读取下一个块。

按特定字符分隔值可以工作,具体取决于您的值:如果您的字符串不使用分隔字符,例如逗号,则可以使用逗号分隔符保存值。当没有已知是有用的分离字符时,事情就会变得有趣。在这种情况下,典型的方法是将引号与合适的转义字符一起使用,例如,C 和 C++ 用于特定字符串文字

  • 通常字符串以单引号开头"
  • 要将引号嵌入到字符串中,它通过反斜杠进行转义,例如 """ .
  • 要嵌入转义字符反斜杠,它使用两个反斜杠,例如 "\" .

有时使用的另一种方法是将值与大小前缀组合在一起。不过,使用什么取决于确切的需求。

当您使用逗号作为分隔符时,在读取格式化值(例如整数)时可能需要跳过逗号:它们不容易读取逗号,只是忽略它可能不合适。如果缺少,则显然是格式错误。您可能希望使用操纵器在存在时额外加一个逗号:

std::istream& comma(std::istream& in) {
    std::istream::sentry cerberos(in);
    if (in && in.peek() == ',') {
        in.ignore();
    }
    else {
        in.setstate(std::ios_base::failbit);
    }
    return in;
}
// ...
int i, j;
if (in >> i >> comma >> j) { ... }

输入表达式应读取两个逗号分隔的整数,如果任一值不是int或它们未用逗号分隔,则失败。

如果我

正确理解您的问题,您希望知道如何以可以再次读取的格式存储数据(大概在另一个C++程序中)。

如果是这样,那么您可以通过多种方式执行此操作:

最常见(也是最简单的)方法是通过以下方式:

  1. 空格分隔(例如): value1 value2 value3
  2. 逗号(这将生成一个逗号分隔的文件,通常称为 CSV 文件) 1,2,3 .
  3. 或者,任何字符: 1#2#3

这样您就可以像以前一样使用std::getline(例如,对于 CSV):

char delim = ',';
while(std::getline(input_stream, temporary_string, delim) {
    //data handling goes here...
}

当然,由于这是一个幼稚的例子(即您的数据被结构化为表格),您必须调整代码以处理通常跨越多行的多方面数据,方法是读取数据块并根据格式解析这些块。

复杂示例(卫星坐标):

1.1 1.2 1.3 1.4 1.5
1.6   1.7 1.8 1.9
2.0        
2.0
2.1 2.2 2.3 2.4 2.5
2.1     2.4

这是空格分隔的,具有以下格式:

  1. 每个数据点都以以下模式存储:数据、空间。
  2. 如果数据点不存在,则由空格表示,除非是最后一个不存在的数据点,其中所有其他输出都是截断为换行符。