SQLiteBlobTooBigException:行太大,无法写入CursorWindow,同时写入数据库

时间:2019-07-19 07:24:25

标签: java android sqlite

当我尝试添加到android上的sqllite DB时,我看到以上错误。我正在使用cloudant库。这是堆栈跟踪:

2019-07-17 18:04:48.292 5522-5753/org.iprd.identity E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT docs.docid, docs.doc_id, revid, sequence, current, deleted, parent, json FROM revs, docs WHERE docs.docid=? AND revs.doc_id=docs.doc_id AND revid=? ORDER BY revs.sequence LIMIT 1
2019-07-17 18:04:48.302 5522-5522/org.iprd.identity E/DatabaseImpl: Failed to create document
    java.util.concurrent.ExecutionException: android.database.sqlite.SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1
        at java.util.concurrent.FutureTask.report(FutureTask.java:123)
        at java.util.concurrent.FutureTask.get(FutureTask.java:193)
        at com.cloudant.sync.internal.documentstore.DatabaseImpl.get(DatabaseImpl.java:1084)
        at com.cloudant.sync.internal.documentstore.DatabaseImpl.create(DatabaseImpl.java:925)

我以前从未遇到过此问题,但是,我最近进行了更改,并开始使用3rd party工具为我提供一些图像。使用此新工具,图像尺寸似乎比以前更大。通过对图像进行Base64编码,我将这些图像作为字符串存储在数据库中。但是,使用此新工具,在存储图像时,出现了上述异常。

我有一个单元测试,我尝试使用从该图像生成的字符串之一进行测试,但这还会引发一个错误,即字符串大小太大甚至无法编译。

解决此问题的最佳方法是什么? -

  1. 我当时想做的就是将图像存储在设备本身中,而只是将路径存储在DB中。

  2. 我们可以对图像进行压缩以减小其文件大小吗?

  3. 是否可以调整某些数据库设置以确保它可以处理更大的图像大小?

谢谢!

6 个答案:

答案 0 :(得分:0)

将图像存储在应用程序专用存储下的设备中,并将该图像路径存储在数据库中。

答案 1 :(得分:0)

  

我当时想做的是将图像存储在设备中   本身,只是将路径存储在数据库中。

不回答,因为您最好回答这个问题。

  

我们可以对图像进行一些压缩以减少其文件吗   大小?

可能,但这并不一定能消除问题。就像您将图像压缩为2Mb(光标窗口的 4Mb 限制的一半)一样,类似的情况是一次光标窗口只能容纳1行。结果可能是非常差的性能,并且瓶颈不是真正的SQLite,而是处理游标。

  • 不推荐

另一种解决方案,但仍然很昂贵,是将图像存储在零件/块中,可以找到一个示例(请注意,未进行任何调整来建立256kb的卡盘大小)here注意到响应时间很短

  • 不推荐,但是如果性能不成问题不是问题,那么可以解决

不需要额外压缩/解压缩的开销的解决方案是将图像或超过设置大小的图像存储在文件系统(例如外部存储)中,并存储路径或路径的一部分。

  • 后一种选项将较小的图像存储在数据库中,将较大的图像存储为文件,可以利用35% Faster Than The Filesystem)。

  • answer here中的混合路径/斑点解决方案示例。

    • 注意。该示例可以用作存储路径或混合解决方案的基础。
  • 推荐

  

是否可以调整某些数据库设置以确保它可以处理   图片更大吗?

是的。

您可以考虑:-

答案 2 :(得分:0)

是的-这是一个真实的问题。但是我为此实现了一个修复程序。我们基本上在文档中使用生物特征识别图像。我现在要做什么:将各个生物识别实体(例如指纹)存储在单独的文档中。有一个具有此文档ID的主文档。

例如:我们捕获一个人的拇指和食指。我们存储了2个文档来存储它们-让我们将它们称为thumb.json和index.json。它们的文档ID分别为thumb_100和index_100。现在,我们有了一个主要的生物识别文档,如下所示:

“拇指”:“ thumb_100” “ index”:“ index_100”

这有助于我们从主文档中获得拇指和食指的指纹。更重要的是,它可以确保单个行的大小不超过限制或引起异常,如前所述。

答案 3 :(得分:0)

我发现如何使用length()和substr()仅请求1MB(CursorWindow的最大值为2MB),也许它会help。 (以防用户遇到此问题,您需要避免例外情况)此外,您可以将context.getContentResolver().query()与仅包含相关列的选择一起使用,这样就不会加载与其他列相关的数据(并且节省一些空间)。否则,我建议您建议的第一个选项是将文件存储在内部存储器中,并将文件路径存储在数据库中。

答案 4 :(得分:0)

如果要在SQLite或Room中将图像另存为字节数组,则应压缩该字节数组。

像这样

Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();

答案 5 :(得分:0)

我解决了以下问题:当我从远程银行搜索图像时,我会检查它们的大小,如果它们大于500 kb,则会进行调整大小的过程。

produto.setImagem_img(imagemTratada(rs.getBytes("imagem_img")));

神奇的方法:

private byte[] imagemTratada(byte[] imagem_img){

    while (imagem_img.length > 500000){
        Bitmap bitmap = BitmapFactory.decodeByteArray(imagem_img, 0, imagem_img.length);
        Bitmap resized = Bitmap.createScaledBitmap(bitmap, (int)(bitmap.getWidth()*0.8), (int)(bitmap.getHeight()*0.8), true);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        resized.compress(Bitmap.CompressFormat.PNG, 100, stream);
        imagem_img = stream.toByteArray();
    }
    return imagem_img;

}