在安卓开发中,有时需要将本地文件(如图片、音频、文档等)以二进制形式存储到数据库中,例如将文件内容转换为字节数组(BLOB)存入SQLite数据库,这种场景常见于需要集中管理文件数据、实现文件内容检索或跨设备同步的需求。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
通过FileInputStream
读取为字节数组。
public byte[] getFileBytes(String filePath) throws IOException { File file = new File(filePath); try (FileInputStream fis = new FileInputStream(file)) { return fis.readAllBytes(); // API 26+,低版本需手动读取 } }
低版本兼容方案:
public byte[] getFileBytesCompat(String filePath) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try (FileInputStream fis = new FileInputStream(filePath)) { byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } } return outputStream.toByteArray(); }
设计表结构,至少包含以下字段:
id
:主键,唯一标识文件。fileName
:文件名。filePath
:原始文件路径(可选)。fileSize
:文件大小(可选)。fileContent
:BLOB类型,存储文件字节数据。CREATE TABLE Files ( id INTEGER PRIMARY KEY AUTOINCREMENT, fileName TEXT NOT NULL, filePath TEXT, fileSize INTEGER, fileContent BLOB );
将文件字节数组存入数据库。
public void insertFileToDB(String filePath, SQLiteDatabase db) { String fileName = new File(filePath).getName(); long fileSize = new File(filePath).length(); byte[] fileBytes = getFileBytesCompat(filePath); // 读取文件为字节数组 ContentValues values = new ContentValues(); values.put("fileName", fileName); values.put("filePath", filePath); values.put("fileSize", fileSize); values.put("fileContent", fileBytes); db.insert("Files", null, values); }
将BLOB数据还原为文件。
public void saveBlobToFile(byte[] blob, String targetPath) throws IOException { try (FileOutputStream fos = new FileOutputStream(targetPath)) { fos.write(blob); } } // 示例:从数据库读取并恢复文件 public void restoreFileFromDB(int fileId, SQLiteDatabase db, String targetDir) { Cursor cursor = db.query("Files", new String[]{"fileName", "fileContent"}, "id=?", new String[]{String.valueOf(fileId)}, null, null, null); if (cursor.moveToFirst()) { String fileName = cursor.getString(0); byte[] fileBytes = cursor.getBlob(1); String targetPath = targetDir + "/" + fileName; saveBlobToFile(fileBytes, targetPath); // 保存为本地文件 } cursor.close(); }
问题 | 解决方案 |
---|---|
大文件处理 | 文件过大可能导致内存溢出(readAllBytes 受限于堆内存)。解决方案:分块读取,或使用 ContentResolver 结合InputStream 流式处理。 |
性能优化 | 频繁读写大文件会影响性能。 解决方案: 仅存储必要字段(如文件路径,非内容)。 使用异步任务处理数据库操作。 |
数据库容量限制 | SQLite单个BLOB最大约1GB,总容量受设备存储限制。 解决方案:对超大文件使用分片存储或云存储。 |
// 1. 打开数据库 SQLiteOpenHelper dbHelper = new SQLiteOpenHelper(context, "fileDB.db", null, 1) { @Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE Files (id INTEGER PRIMARY KEY AUTOINCREMENT, fileName TEXT, fileContent BLOB)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} }; SQLiteDatabase db = dbHelper.getWritableDatabase(); // 2. 插入文件 String filePath = "/storage/emulated/0/test.txt"; insertFileToDB(filePath, db); // 3. 读取文件 restoreFileFromDB(1, db, "/storage/emulated/0/restored");
解答:
可通过文件名或文件路径查询数据库。
Cursor cursor = db.query("Files", new String[]{"id"}, "filePath=?", new String[]{filePath}, null, null, null); if (cursor.getCount() > 0) { // 文件已存在,处理逻辑(如更新或跳过) } cursor.close();
解答:
在数据库表中添加对应字段,并在插入时计算或获取元数据。
ALTER TABLE Files ADD COLUMN createTime INTEGER; -存储时间戳 ALTER TABLE Files ADD COLUMN fileMd5 TEXT; -存储MD5值
插入时:
values.put("createTime", System.currentTimeMillis()); values.put("fileMd5", calculateMD5(fileBytes)); // 需实现MD5计算方法