在Android开发中面对一些轻量级的数据库,使用最多的就是SQLite,对于其他数据类型的操作,相信很多初学者都已经知道了,但是对于图片、音乐这类的数据也是可以保存的SQLite的(虽然在实际的开发中没有人会把图片和音乐等保存到数据库,因为对于数据库来说10+KB的数据已经是很庞大的,很快就会因此造成查询性能下降)但是对于知识体系来说有必要了解下数据库保存二进制数据类型。
实际上计算机的存储在物理上是都二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的编码层次上有差异。简单来说,文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等;二进制文件是基于值编码的文件,你可以根据具体应用,指定某个值是什么意思(也可以看作是自定义编码)。一般文本文件基本上是定长编码的(也有非定长的编码如UTF-8)。而二进制文件可看成是变长编码的,因为是值编码嘛,多少个比特代表一个值,完全由你决定。比如说BMP文件举例子吧,其头部是较为固定长度的文件头信息,前2字节用来记录文件为BMP格式,接下来的8个字节用来记录文件长度,再接下来的4字节用来记录bmp文件头的长度。而对于一个文件流”01000000_01000001_01000010_01000011”(下划线”_”,为了增强可读性手动添加的),第一个8比特”01000000”按ASCII码来解码的话,所对应的字符是字符”A”,同理其它3个8比特可分别解码为”BCD”,即这个文件流可解释成“ABCD”,然后记事本就将这个“ABCD”显示在屏幕上。
总而言之,图片是一种比文本文件特殊的二进制文件,在SQLite提供了BLOB类型用于保存二进制数据,知道了原理之后,保存二进制就很简单了,只需二步:
其实存储图片与存储普通数据本质上没有什么不同,就是多了转为二进制的步骤,其他的都一样,没看过的可以参考Android入门——数据存储之SQLite详解与简单应用
package crazymo.com.saveimagetodb.service;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* auther: MO
* Date: 2017/1/11
* Time:18:33
* Des:
*/
public class SQLiteHelper extends SQLiteOpenHelper {
private static final String dbname="REBOT.db";
private static final int version=1;
private static SQLiteHelper dbHelper;
//也可以不指定字段的类型、长度,因为int类型也可以保存Char类型的创建学生表
private final String createTb="CREATE TABLE User (_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR2,avatar BLOB)";
public SQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public SQLiteHelper(Context context){
super(context, dbname, null, version);
}
public static SQLiteHelper getInstance(Context context) {
if (dbHelper == null) { //单例模式
dbHelper = new SQLiteHelper(context);
}
return dbHelper;
}
@Override
public void onCreate(SQLiteDatabase db) {
// 创建一个数据库表 User ,字段:_id、name、avatar。
db.execSQL(createTb);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
数据库操作:保存和读取图片
package crazymo.com.saveimagetodb.service;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.List;
import crazymo.com.saveimagetodb.bean.User;
import crazymo.com.saveimagetodb.util.BitmapUtil;
/**
* auther: MO
* Date: 2017/1/11
* Time:18:41
* Des:
*/
public class DBOperate {
private SQLiteHelper dbhelper;
private Context context;
//要操作数据库操作实例首先得得到数据库操作实例
public DBOperate(Context context) {
this.context=context;
this.dbhelper = SQLiteHelper.getInstance(context);
}
public void saveImage(){
SQLiteDatabase db = dbhelper.getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put("_id", 1);
cv.put("avatar", bitmabToBytes(context));//图片转为二进制
db.insert("User", null, cv);
db.close();
}
public byte[] readImage(){
SQLiteDatabase db = dbhelper.getWritableDatabase();
Cursor cur=db.query("User", new String[]{"_id","avatar"}, null, null, null, null, null);
byte[] imgData=null;
if(cur.moveToNext()){
//将Blob数据转化为字节数组
imgData=cur.getBlob(cur.getColumnIndex("avatar"));
}
return imgData;
}
//图片转为二进制数据
public byte[] bitmabToBytes(Context context){
//将图片转化为位图
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
int size = bitmap.getWidth() * bitmap.getHeight() * 4;
//创建一个字节数组输出流,流的大小为size
ByteArrayOutputStream baos= new ByteArrayOutputStream(size);
try {
//设置位图的压缩格式,质量为100%,并放入字节数组输出流中
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
//将字节数组输出流转化为字节数组byte[]
byte[] imagedata = baos.toByteArray();
return imagedata;
}catch (Exception e){
}finally {
try {
bitmap.recycle();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return new byte[0];
}
}
简单测试(代码有些不规范)
package crazymo.com.saveimagetodb;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import butterknife.Bind;
import butterknife.OnClick;
import crazymo.com.saveimagetodb.service.DBOperate;
public class MainActivity extends AppCompatActivity {
@Bind(R.id.save_btn)
Button saveBtn;
@Bind(R.id.read_btn)
Button readBtn;
@Bind(R.id.show_imv)
ImageView showImv;
private String url;
private DBOperate dbOperate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
butterknife.ButterKnife.bind(this);
init();
}
private void init(){
dbOperate=new DBOperate(this);
}
@OnClick({R.id.save_btn,R.id.read_btn})
void onClick(View view){
switch (view.getId()){
case R.id.read_btn:
readImage();
break;
case R.id.save_btn:
saveImage(url);
break;
default:
break;
}
}
private void readImage(){
byte[] imgData=dbOperate.readImage();
if (imgData!=null) {
//将字节数组转化为位图
Bitmap imagebitmap = BitmapFactory.decodeByteArray(imgData, 0, imgData.length);
//将位图显示为图片
showImv.setImageBitmap(imagebitmap);
}else {
showImv.setBackgroundResource(android.R.drawable.menuitem_background);
}
}
private void saveImage(String url){
dbOperate.saveImage();
}
}