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:
}
我的问题是保存的文件只能用 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:
}