我正在生成随机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字符。