【发布时间】:2018-12-01 07:42:43
【问题描述】:
在将数据库作为 JSON 字符串的文本文件写入磁盘时,我一直在尝试如何最有效地构建最终转换为 blob 以下载到磁盘的文本字符串。
有许多问题指出不要在循环中使用+ 运算符连接字符串,而是将组件字符串写入数组,然后使用join 方法构建一个大字符串。
Jeol Mueller 的 here 是我遇到的最佳解释:
在 JavaScript(以及 C#)中,字符串是不可变的。它们永远无法更改,只能用其他字符串替换。您可能知道 combine + "hello" 不会直接修改组合变量 - 该操作会创建一个新字符串,该字符串是将两个字符串连接在一起的结果,但如果出现以下情况,您必须将该新字符串分配给组合变量你想改变它。
所以这个循环正在做的是创建一百万个不同的字符串对象,并丢弃其中的 999,999 个。创建这么多大小不断增长的字符串并不快,现在垃圾收集器在这之后有很多工作要做清理。”
thread here 也很有帮助。
但是,使用join 方法并不允许我构建我想要的字符串而不会出现错误:
分配大小溢出
我试图将数据库中的 50,000 个 JSON 字符串写入一个文本文件,但无论如何它都可能太大了。我认为它达到了 350MB 以上。我只是在测试我的应用程序的限制,并选择了比应用程序用户可能创建的要大得多的东西。所以,这个测试用例很可能是不合理的。
不过,这给我留下了三个关于使用大字符串的问题。
-
对于相同数量的整体数据,更改在单个
join操作中加入的数组元素的数量是否会影响不达到分配大小溢出的效率?例如,我尝试将 JSON 字符串写入每个维度 100(然后是 50)元素的伪 3-D 数组;然后循环通过外部两个维度将它们连接在一起。 100^3 = 1,000,000 或 50^3 = 125,000 都提供了足够多的条目来容纳 50,000 个 JSON 字符串。我知道我在这里不包括 0 索引。
因此,第一次尝试将 50,000 个字符串保存在从 a[1][1][1] 到 a5[100][100] 的数组中,然后是 a[1][1][1 ] 到 a[20][50][50] 在第二次尝试中。如果维度是从外到内的i,j,k,我加入了每个a[i][j]中的所有k个元素;然后加入所有这些 i x j 连接,最后将所有这些 i 连接到最终的文本字符串中。
所有尝试在完成之前仍然达到分配大小溢出。
那么,如果总数据相同,将 50,000 个较小的字符串合并到一个
join与 50 个较大的字符串之间有什么区别吗?
- 有没有比 join 方法更好、更有效的方法来构建大字符串?
-
Joel Mueller 描述的关于字符串连接的相同原则是否适用于通过
substring减少字符串,例如string = string.substring(position)?第三个问题的上下文是,当我将文本文件作为字符串读取并在写入数据库之前将其分解为其组件 JSON 字符串时,我使用的是文件布局映射的数组;所以,我提前知道了每个 JSON 字符串的长度,并在一个循环中重复三个语句:
l = map[i].l; str = text.substring(0,l); text = text.substring(l).看起来,由于字符串是不可变的,这种反向连接步骤与使用
+运算符进行连接一样低效。在每次迭代时不从文本中删除
str会更有效吗?只跟踪子字符串增加的开始和结束位置作为循环读取整个文本字符串的步骤?
回复有关重复问题的消息
我收到一条消息,我猜是来自 stackoverflow 系统本身,要求我编辑我的问题,解释为什么它与建议的副本不同。
原因是:
建议的副本专门询问单个字符串的最大大小。这里的三个粗体问题都没有询问单个字符串的最大大小,尽管知道这一点很有用。
这个问题询问了构建大型字符串的最有效方法,除了构建大型测试字符串的有效方法之外,建议的副本中的答案中没有解决这个问题。它们没有说明如何构建由实际应用程序数据组成的真实字符串。
此问题提供了几个链接,指向有关构建大字符串的效率的一些信息,这些信息可能对那些对超过最大大小感兴趣的人有所帮助。
这个问题也有一个具体的背景,说明为什么要构建大字符串,这导致了一些关于如何以更有效的方式处理这种情况的建议。尽管从最严格的意义上说,他们没有按标题专门解决问题,但他们确实解决了所提出问题的更广泛背景,即如何处理大字符串,即使这意味着解决它们的方法。搜索同一主题的人可能会在建议的副本中未提供的这些建议中找到真正的帮助。
因此,尽管提议的副本有些帮助,但在完整的上下文中,它似乎与该问题的真正副本相去甚远。
其他信息
这并没有回答有关构建大字符串的最有效方法的问题,但它指的是 cmets 关于如何绕过字符串大小限制的问题。
将每个组件字符串转换为一个 blob 并将它们保存在一个数组中,然后将 blob 数组转换为单个 blob,从而实现了这一点。我不知道单个 blob 的大小限制是多少,但在另一个问题中确实看到了 800MB。
可以在here 找到创建 blob 以将数据库写入磁盘然后再次读回它的过程(或起点)。
关于将 blob 或字符串在客户端生成时写入磁盘的想法,而不是生成一个巨大的字符串或 blob 以供下载,虽然是最合乎逻辑和最有效的方法,但在此处介绍的场景中可能无法实现的离线应用程序。
根据此question,网络扩展程序不再有权访问通过文件 API 完成此操作所需的特权 javascript 代码。
我问过这个question,它与 Streams API 写入流方法和称为 StreamSaver 的东西有关。
【问题讨论】:
-
您是否考虑过寻找一种解决方案,在写入之前不需要将文件的全部内容放在一个字符串中?
-
我想过从字符串的某些部分制作几个 blob,然后附加 blob。但是没有尝试,因为我认为将 blob 放在一起比字符串需要更多的内存。我不希望用户必须下载多个文件,但我想这可能是一种选择。如果字符串或 blob 可以分段写入磁盘上的单个文件,而无需用户安装某些功能,那将是更好的选择。谢谢。
-
哦,你正在创建一个data-url客户端供用户下载?这有点不同。我假设服务器端。我仍然建议尝试找到一些替代一个巨大的字符串。
-
是的。也许,我应该在这个问题上更具体。这一切都发生在客户端。如果扩展 API 提供了一种方法,那也适用于我的情况。
-
您可以查看
Fileinterface(或者更可能是它的基础Blobinterface,它可能对空间有更高的容忍度。您可以从现有的Blobs 创建新的Blobs,所以根据您构建数据的方式,您可以创建一批Blobs,然后将它们全部提取。
标签: javascript arrays string