Android sqlite 如何正确地检索大于 1 MB 的 blob

Android sqlite how to retrieve blob > 1 mb in chunks correctly

我的问题是保存的文件只能用 Google Pdf 查看器打开,pdf 文件有部分不清楚,adobe acrobat 根本打不开,因为文件已损坏。创建的文件肯定有问题,但我没有看到它。

现在是上下文: 我使用 dbflow 来处理与服务器的 sqlite 数据库同步。保存时没有错误,如果我直接将文件保存到下载目录,文件可以正常查看。 blob 保存在一个只有 id 和 blob 的新 table 中,并按如下方式检索:

  DatabaseDefinition database = FlowManager.getDatabase(Database.NAME);
        AndroidDatabase android = (AndroidDatabase) database.getWritableDatabase();
        Cursor rawQuery = android.rawQuery("select length(blob) from table where id=" + String.valueOf(id), null);
        int blobLength = 0;
        if (rawQuery != null) {
            while (rawQuery.moveToNext()) {
                blobLength = rawQuery.getInt(0);
            }
            rawQuery.close();
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );

        final int CHUNK_SIZE = 1024 * 4;

        loop:
        for(int i = 0; i< blobLength/CHUNK_SIZE + 1; i++) {
            int ceiling =  (i+1)*CHUNK_SIZE > blobLength ? blobLength : (i+1) *CHUNK_SIZE;
            Cursor readBlobChunk =  android.rawQuery("select substr(blob, " +  i*CHUNK_SIZE + 1 + "," + ceiling + ") from table where id =" + String.valueOf(id), null);

            try {
                if (readBlobChunk != null) {
                    readBlobChunk.moveToFirst();
                    outputStream.write(readBlobChunk.getBlob(0));
                }
            } catch(ArrayIndexOutOfBoundsException e ) {
                Log.e(TAG, "blob chunk read exception", e);
                break loop;
            } catch (IOException e) {
                Log.e(TAG, "blob chunk io exception", e);
            }
            readBlobChunk.close();
        }
        byte[] picture = outputStream.toByteArray();
        try {
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            Log.e(TAG, " io exception", e);
        }

        //save file from bytearray to download directory
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(advResource,false);
            out.write(picture);
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            Log.e(TAG, "exception", e);
        }  catch (IOException e) {
            Log.e(TAG, "exception", e);
        }

我说过,根据块大小,文件看起来可能更好也可能更差。

您想一次读取 CHUNK_SIZE 个字节。 虽然偏移量是正确的,但给定 substr() 的长度随着每个块的增加而增加:

        int ceiling =  (i+1)*CHUNK_SIZE > blobLength ? blobLength : (i+1) *CHUNK_SIZE;
        Cursor readBlobChunk =  android.rawQuery("select substr(Picture, " +  i*CHUNK_SIZE + 1 + "," + ceiling + ") from table where id =" + String.valueOf(id), null);

如果跟踪剩余字节,逻辑会变得更简单:

remaining = blobLength;
while (remaining > 0) {
    int chunk_size = remaining > CHUNK_SIZE ? CHUNK_SIZE : remaining;
    query("SELECT substr(Picture, "+ (i*CHUNK_SIZE+1) + ", " + chunk_size + "...");
    ...
    remaining -= chunk_size:
}