許多 Android 開發者初學時會嘗試將圖片、音頻轉為 `byte[]` 直接存入 SQLite 的 BLOB 字段。雖然技術上可行,但**強烈不推薦**用於生產環境。本文分析缺點並給出行業標準做法:文件落地存儲 + 數據庫存路徑。
| 缺點 | 影響 |
|---|---|
| 數據庫體積膨脹 | SQLite 單文件建議不超過 100-200MB,大文件快速達到上限,導致讀寫性能驟降、備份困難。 |
| 內存壓力大 | 讀取 BLOB 需一次性加載到內存 (`Cursor.getBlob()`),易導致 OOM,尤其對大圖/長音頻。 |
| 事務開銷高 | 寫入大 Blob 會長時間鎖定數據庫,阻塞其他查詢。 |
| 無法利用系統優化 | 無法使用 `BitmapFactory.decodeFile` 采樣加載、MediaPlayer 直接播放文件路徑、Glide/Picasso 緩存機制等成熟方案。 |
CREATE TABLE media (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT NOT NULL, -- 'image' / 'audio'
mime_type TEXT, -- 'image/jpeg', 'audio/mpeg'
file_path TEXT NOT NULL, -- 存儲文件絕對路徑 或 content:// Uri
file_size INTEGER,
duration INTEGER, -- 音頻時長(ms)
width INTEGER, height INTEGER,-- 圖片尺寸
created_at INTEGER DEFAULT (strftime('%s','now'))
);
// 1. 保存文件到內部存儲
File dir = new File(context.getFilesDir(), "images");
if (!dir.exists()) dir.mkdirs();
File imageFile = new File(dir, "IMG_" + System.currentTimeMillis() + ".jpg");
try (FileOutputStream fos = new FileOutputStream(imageFile)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
}
// 2. 插入數據庫記錄路徑
ContentValues values = new ContentValues();
values.put("type", "image");
values.put("mime_type", "image/jpeg");
values.put("file_path", imageFile.getAbsolutePath()); // 或 Uri.toString()
values.put("file_size", imageFile.length());
values.put("width", bitmap.getWidth());
values.put("height", bitmap.getHeight());
db.insert("media", null, values);
// 查詢路徑
String path = cursor.getString(cursor.getColumnIndex("file_path"));
// 圖片:使用 Glide/Picasso 直接加載路徑,自動處理緩存、采樣、生命周期
Glide.with(context).load(new File(path)).into(imageView);
// 音頻:MediaPlayer 直接設置數據源
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(path);
mp.prepareAsync(); // 異步準備
若文件極小(< 10-20KB),如用戶頭像縮略圖、狀態圖標,**可考慮存 BLOB**,避免大量小文件 IO 開銷。但仍建議設置上限並評估總量。
**大文件落盤,路徑入庫** 是 Android 存儲鐵律。善用文件系統與媒體庫 API,您的應用將更輕量、高效、穩定。