如何在一个文件中存储多个随机Blob



我正在生成随机Blob(在我的情况下,它是由任意非零长度的std::vector<unsigned char>组成的std::string)。Blob是随机的,因为它们可以是给定大小范围内的任何大小,并且它们包含随机的无符号字符。

我正试图将这些Blob写入一个文件(比如Blobs.txt),这样我的文件中的每一行都会给我一个生成的Blob。例如,Blobs.txt的第一行将包含第一个生成的blob,Blob.txt的最后一行将包含最后一个生成的blob,依此类推

我目前面临的问题是blob本身可能包含换行符(n)。因此,我的Blobs.txt中的行数可能不等于生成的Blob数。

由于斑点是随机的,我无法对每个斑点的样子做出任何假设。

我发现问题是由单个文件中换行符的两个不同用例的干扰引起的,一个在blob内容本身中,另一个作为文件中的分隔符。而且,要解决这个问题,我要么必须将换行符替换为blob内容中的其他字符,然后将它们放在Blobs.txt中,要么,我必须将Blobs.txt文件中的blob分隔符从换行符更改为无法出现在blob内容中(不确定第二种解决方案是否可行)。

我知道我将在Blobs.txt中存储固定数量的Blob。

我想在Blobs.txt文件中的每个blob(例如"001:<blob 1 string>")之前添加一些明确的固定长度编号,但这似乎并不能解决问题,因为"001:"本身可能存在于某个blob中,而且我们事先不知道blob的大小。

一种可能的解决方案是将偏移量写入一个单独的文件(比如Blob_Offsets.txt)中,我在其中存储这些Blob中的每个Blob的大小,并使用它们来查找Blobs.txt。我不想依赖内存中的结构,因为一旦它们消失,我就无法理解Blobs.txt

我想知道是否真的需要创建一个单独的偏移文件,因为这会增加读取blob时的磁盘访问次数?有更好的方法来解决这个问题吗?

您是否致力于使用一个"行";每个斑点?我认为你会很难做到这一点,尤其是如果你的斑点中有新的线条。

我想我应该使用二进制方法。以binary模式打开文件,这样新行就不会被转换为CR-LF(在Windows中)。使用stream.write写一个二进制计数,然后是您的blob。读取文件时,使用stream.read读取计数值,然后将那么多字节读取到blob中。

我的文件中的每一行都会给我一个生成的Blob

Blobs.txt文件中的blob分隔符从换行符更改为其他字符

不兼容。您希望在文本编辑器中的不同行上显示的内容必须用n(在linux上,或在windows上的rn,或其他什么)分隔;不能使用其他字符,因为编辑器不会将其解释为换行符,因此不会在单独的行中显示它们。

考虑到这一点,您只能更改n,它们最初是而不是,意味着它们是行分隔符,即那些随机出现在Blob中的CCD_23。通过逃离它们可能是一种方式,例如

#include <iostream>
#include <string>
#include <range/v3/action/join.hpp>
#include <range/v3/view/transform.hpp>
using namespace ranges::views;
using namespace ranges::actions;
int main()
{
// the string that unfortunately contains n already
std::string s{"hellonworld"};
// indeed this prints 2 lines
std::cout << s << std::endl;
// function to escape n and  itself
auto constexpr escape = [](char c){
return c == 'n' ? "\n" :
(c == '\' ? "\\" : std::string{c});
};
std::string s2 = s | transform(escape) // this is a range of strings now
| join; // so we join all the strings together
std::cout << s2 << std::endl; // prints 1 line
}

正如评论中所建议的,我已经通过转义了n控制字符,由于是转义字符,如果我在字符串中遇到它,我也必须转义它,这意味着\(文本中的"true"退格)必须变成\\("true"双退格)。

转义很容易,因为您想转义单个字符;取消转义有点复杂,因为转义字符不是每个1个字符,而是2个:转义字符和转义字符。因此,要取消escape,必须将逃跑和逃跑的角色组合在一起。例如,原始字符串中的字符(参见下面的Trivia部分)R"(hel\nlonworld)",其中您已经转义了以获得\,换行符获得了n,应该像["h","e","l",R"(\)","n","l","o",R"(n)","w","o","r","l","d"]中那样进行分组,我认为您可以通过ranges::views::group进行分组;则通过保持长度为1的字符串不变并取消对长度为2的字符串的捕获(即R"(\)"R"(n)" would become\and\nrespectively); then you would联接`.


三叉戟

代替

std::string s{"hel\nlonworld"};

您可以使用原始字符串文字(此处为数字6)来避免转义字符:

std::string s{R"(helnlo
world)"};

其中n实际上只是后面跟着字母n,而对于换行,我确实按下了字符串中间的输入;如果您的编辑器允许,您可以将该字符放入文本中;在Vim中,它显示为这样的

std::string s{R"(helnlo^Mworld)"};

其中^M是通过Ctrl-v输入获得的单个换行符。

如果文件大小不是问题,可以用Base64格式对Blob进行编码
该格式不使用'n'字符,通常用于在Web上将二进制数据表示为ASCII字符。

最新更新