使用localStorage进行JavaScript字符串压缩

20

我在一个项目中使用localStorage,需要存储大量的数据,主要是int、bool和string类型。我知道javascript的字符串是unicode编码的,但是当它们被存储在localStorage中时,它们是否仍然是unicode编码?如果是,我是否可以压缩字符串以使用unicode字节中的所有数据,或者应该只使用base64并少量压缩?所有数据都将作为一个大字符串存储。

编辑:现在我想了一下,base64几乎不进行任何压缩,数据已经是base64形式,a-zA-Z0-9 ;:共65个字符。


我认为这不是推荐做法。我认为每个实现都可能不同。 - KARASZI István
localStorage 是 Unicode 编码的吗?还是 JavaScript 是?我相当确定 JavaScript 字符串是 Unicode 编码的,但我不知道 localStorage 的字符串是否也是。 - invisible bob
我认为所有存储在localStorage中的内容都应该按照存储时的方式返回。但是由于没有人知道,我一直在使用base64编码。 - KARASZI István
我使用包含 的字符串测试了本地存储,其中 是 Unicode 平假名 A,但它无法保存该值(在 Google Chrome 中)。如果它不是 Unicode,那它会是什么?ASCII?拉丁语系列? - invisible bob
1
我想知道是否有任何Javascript压缩算法可以与localStorage一起使用。我正在寻找一些快速的东西,可以在大多数是文本的数据上进行一些压缩。 - HoLyVieR
显示剩余3条评论
5个回答

26

"当存储在localStorage中时,它们是否保持Unicode编码?"

Web Storage工作草案将本地存储值定义为DOMString。 DOMStrings被定义为使用UTF-16编码的16位单位序列。因此,是的,它们保持Unicode编码。

"有没有办法压缩字符串以使用Unicode字节中的所有数据"?...

“Base32k”编码可为每个字符提供15位,使用基于base32k的编码可以利用UTF-16字符中的全部16位,但会失去一位以避免双字字符出错。如果您的原始数据已经进行了base64编码,则每个字符仅使用6位。将这6位编码为base32k可以将其压缩为原始大小的6/15 = 40%。请参见http://lists.xml.org/archives/xml-dev/200307/msg00505.htmlhttp://lists.xml.org/archives/xml-dev/200307/msg00507.html

要进一步缩小大小,可以将base64字符串解码为其完整的8位二进制,并使用某些已知的压缩算法进行压缩(例如,请参见gzip的JavaScript实现),然后对压缩输出进行base32k编码。


+1 针对我即将引用的所有规范进行了引用,并进一步深入。 - ellisbben
但是为什么在谷歌浏览器中,あ不能保存呢?可能是Chrome的问题吗?感谢提供Base32k! - invisible bob
1
你为什么说 'あ' 不能保存?试试这个链接:http://jsbin.com/odadig/4/edit#javascript,html,live。在 Windows 上,使用 Chrome 15 浏览器似乎可以正常工作。在进行实验时,请确保将 HTML 文件以 Unicode 编码(如 UTF8)保存。 - Oren Trutner
这个JS库中的compressToUTF16和decompressFromUTF16函数基本上就是这个答案所描述的(LZW + base32k): http://pieroxy.net/blog/pages/lz-string/index.html - jaredjacobs

7
你可以将其编码为Base64,然后实现一种简单的无损压缩算法,例如行程长度编码或Golomb编码。这不应该太难做,可能会给你一些压缩效果。 Golomb编码 我还发现了JsZip。我想如果兼容的话,你可以查看代码并仅使用算法。
希望这有所帮助。

http://jszip.stuartk.co.uk/


1
我尝试了几种无损编码,但它们经常使用UTF-16字符,这与localStorage不兼容。如果您对内容进行base64编码,则当原始内容为ASCII时,最终内容会比原始内容更大。我将尝试Golomb编码和JSZip,虽然我还没有尝试过它们。这可能会产生良好的结果。 - HoLyVieR
1
这是另一篇可能会引起兴趣的帖子。不确定它是否符合您的用例,但仍然很有趣:http://www.sean.co.uk/a/webdesign/javascript_string_compression.shtm - Laurent Zuijdwijk
我已经尝试了Golomb编码,到目前为止,它在真实数据上表现良好(约5%的压缩率且仍然可读)。考虑到算法的速度,这是我目前看到的最好的。 - HoLyVieR
Base64会增加30%的字符串大小,你确定压缩能够弥补这一点吗? - c69

7

最近我需要将大型JSON对象保存在localStorage中。

首先,是的,它们确实保留了Unicode编码。但不要尝试将类似于对象的东西直接保存到本地存储中。它需要被转换成字符串。

以下是我在将对象转换为字符串之前使用的一些压缩技术(在我的情况下效果很好):

任何数字都可以通过执行 (+num).toString(36) 将其从10进制转换为36进制。例如,数字48346942将变为"ss8qm",其中(包括引号)少了1个字符。可能添加引号实际上会增加字符数。因此,数字越大,收益越好。要将其转换回来,您需要执行类似于 parseInt("ss8qm", 36) 的操作。

如果您要存储一个具有任何重复键的对象,最好创建一个查找对象,其中将缩短的键分配给原始键。例如,为了举例说明,如果您有:

{
    name: 'Frank',
    age: 36,
    family: [{
        name: 'Luke',
        age: 14,
        relation: 'cousin'
    }, {
        name: 'Sarah',
        age: 22,
        relation: 'sister'
    }, {
        name: 'Trish',
        age: 31,
        relation: 'wife'
    }]
}

然后您可以将其制作成:
{
    // original w/ shortened keys
    o: {    
        n: 'Frank',
        a: 36,
        f: [{
            n: 'Luke',
            a: 14,
            r: 'cousin'
        }, {
            n: 'Sarah',
            a: 22,
            r: 'sister'
        }, {
            n: 'Trish',
            a: 31,
            r: 'wife'
        }]
    },

    // lookup
    l: {
        n: 'name',
        a: 'age',
        r: 'relation',
        f: 'family'
    }
}

再次强调,这对于大小和重复性都有好处。在我的情况下,它非常有效。但这取决于主题。

所有这些都需要一个缩小函数和一个扩展函数。

此外,我建议创建一个用于存储和检索本地存储数据的类。我遇到了存储空间不足的问题。因此写入会失败。其他站点也可能写入本地存储,这可能会占用一些空间。有关更多详细信息,请参见此帖子

在我构建的类中,我首先尝试删除具有给定键的任何项。然后尝试setItem。这两行代码都包含在try catch中。如果失败,则假定存储已满。然后它将清除localStorage中的全部内容,以尝试为其腾出空间。然后,在清除之后,再次尝试setItem。这也被包装在try catch中。因为如果字符串本身大于localStorage可以处理的大小,则可能会失败。

编辑:此外,您将经常遇到许多人提到的LZW压缩。我已经实现了它,并且对于小字符串它很有效。但是对于大字符串,它将开始使用无效字符,导致数据损坏。因此,请小心,并且如果您走这条路,请进行测试、测试和测试。


1
我得出了与LZW压缩相同的结论,它无法处理大字符串。至于存储类别,我发现在存储的键上实现过期机制也很有用,这样旧键就不会永远存在。而且如果你正在使用时间戳,那么这些技巧的数量确实非常有用。 - HoLyVieR

0

Javascript中的Base64压缩已经在这篇博客中得到很好的解释。当使用整个框架时,实现也可以在这里找到。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接