บ่อยครั้งที่เวลาเขียนแอพซักตัวที่มีการสร้างฐานข้อมูลขึ้นมา ก็มักจะต้องมีการลองดึงไฟล์ฐานข้อมูลมาเช็คบนคอมเพื่อตรวจสอบว่าโค๊ดทำงานได้อย่างถูกต้องหรือไม่
และผู้ที่หลงเข้ามาอ่านหลายๆคนก็มักจะประสบปัญหาดึงไฟล์ฐานข้อมูลจากแอพบนอุปกรณ์แอนดรอยด์ออกมาดูบนคอมไม่ได้ ซึ่งเป็นปัญหาที่เกิดขึ้นกับมือใหม่แทบจะทุกคน ดังนั้นเจ้าของบล็อกขอจัดบทความสั้นๆสำหรับเรื่องนี้เสียหน่อยดีกว่า
เป็นที่รู้กันอยู่แล้วว่าไฟล์ฐานข้อมูลของแต่ละแอพจะถูกเก็บไว้ในโฟลเดอร์ของแอพตัวเอง
/data/data/<package_name>/databases/
และส่วนใหญ่นั้นจะใช้วิธีดึงฐานข้อมูลออกมาโดยใช้ File Explorer ที่อยู่ใน DDMS หรือ Android Device Monitor แล้วเข้าไปยัง Path ดังกล่าว
แต่ทว่าก็มีผู้ที่หลงเข้ามาอ่านหลายๆคนเจอปัญหาว่าเปิดโฟลเดอร์ data ไม่ได้
ก็ดึงข้อมูลได้ปกตินี่ ไม่เห็นจะมีอะไร
สำหรับผู้ที่หลงเข้ามาอ่านที่ยังไม่เข้าใจว่าเปิดโฟลเดอร์ data ไม่ได้มันเป็นยังไง ให้ลองต่อกับอุปกรณ์แอนดรอยด์ของจริง แล้วใช้ Android Device Monitor หรือ DDMS เปิดโฟลเดอร์ดังกล่าวในเครื่องนั้นๆดู
เพราะว่าเครื่องที่เปิดโฟลเดอร์นั้นได้ จะมีแต่ Emulator เท่านั้น
เคยสังเกตกันมั้ย?
เวลาเปิด Android Device Monitor หรือ DDMS ตรงรายชื่ออุปกรณ์แอนดรอยด์ที่เชื่อมต่ออยู่ เฉพาะ Emulator เท่านั้นที่ตรงช่องเลขเวอร์ชันจะมีต่อท้ายว่า debugซึ่งเป็นการบอกให้รู้ว่าอุปกรณ์แอนดรอยด์ตัวนั้นๆเป็น Debug Device หรือมีไว้สำหรับทดสอบเท่านั้น แต่ทว่าเครื่องที่ผู้ที่หลงเข้ามาอ่านใช้ๆกันอยู่นั้น เป็น Production Device ไม่ใช่เครื่องทดสอบซักหน่อย (ก็ซื้อมาจากร้านค้าที่วางขายตามท้องตลาด)
ซึ่ง Debug Device จะมีความพิเศษตรงที่สามารถเข้าถึงไฟล์ได้ทุกที่ภายในเครื่อง (เพราะว่ามันใช้ทดสอบนั่นเอง) แต่ Production Device จะไม่สามารถเข้าถึงได้ เพื่อป้องกันอันตรายที่อาจจะเกิดขึ้นได้ ดังนั้นจึงทำให้เปิดเข้าไปยังโฟลเดอร์ดังกล่าวไม่ได้
แล้วจะแก้ปัญหายังไงดี?
วิธีแก้ปัญหาจะมีอยู่ด้วยกันสองวิธี คือวิธีแรก - Root เครื่องซะสิ
เมื่อปัญหาที่แท้จริงนั้นเกิดจากเรื่องความปลอดภัย ถ้างั้นก็ลองแหกความปลอดภัยดูสิ เพราะการ Root เครื่องจะทำให้สามารถเข้าถึงระดับ Root ได้ จึงสามารถเข้าถึงไฟล์ได้ทั้งเครื่อง เหมือนกับ Debug Deviceพอ Root เรียบร้อยแล้วก็จะสามารถใช้แอพ File Explorer ที่รองรับ Root Access อย่าง ES File Explorer เพื่อเข้าไปก๊อปไฟล์ตามที่ต้องการได้เลย แต่ว่าต้องก๊อปผ่านแอพบนเครื่องแอนดรอยด์เท่านั้น แล้วต้องก๊อปลงคอมพิวเตอร์อีกที
วิธีที่สอง - เขียนโค๊ดให้ก๊อปไฟล์ออกมา
เนื่องจากโฟลเดอร์ดังกล่าวถูกป้องกันไม่ให้เข้าถึงได้ แต่ก็อย่าลืมว่าแอพที่เป็นเจ้าของโฟลเดอร์นั้นๆจะเข้าถึงโฟลเดอร์ได้อย่างปกติ ดังนั้นโค๊ดคำสั่งใดๆก็ตามที่อยู่ในแอพนั้น จะสามารถเข้าถึงโฟลเดอร์นั้นได้ทั้งหมดดังนั้นก็ไปเขียนให้แอพนั้นมันดึงฐานข้อมูลออกมาเองเลยสิ!!!
public boolean exportDatabaseFile(Context context, String dbName) {
try {
File dbFile = context.getDatabasePath(dbName);
File exportFile = new File(Environment.getExternalStorageDirectory() + "/" + dbName);
FileInputStream fileInputStream = new FileInputStream(dbFile);
FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
FileChannel fileInputChannel = fileInputStream.getChannel();
FileChannel fileOutputChannel = fileOutputStream.getChannel();
fileInputChannel.transferTo(0, fileInputChannel.size(), fileOutputChannel);
fileInputStream.close();
fileOutputStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
นี่คือคำสั่งก๊อปไฟล์จากฐานข้อมูลของแอพนั้นๆมาเก็บไว้ใน External Storage โดยเวลาใช้งานจริงๆจะเป็นแบบนี้
ก่อนอื่นต้องสมมติไฟล์ Database Helper ขึ้นมาก่อน
MyDbHelper.java
package com.akexorcist.exportdatabase;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
class MyDbHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "bakery_store";
private static final int DB_VERSION = 1;
public static final String TABLE_NAME = "product";
public static final String COL_NAME = "name";
public static final String COL_PIECE_PRICE = "piece_price";
public static final String COL_CAKE_PRICE = "cake_price";
public MyDbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME +" (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COL_NAME + " TEXT, " + COL_PIECE_PRICE + " INTEGER, " + COL_CAKE_PRICE + " INTEGER);");
db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE
+ ", " + COL_CAKE_PRICE + ") VALUES ('Chocolate Fudge', 95, 750);");
db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE
+ ", " + COL_CAKE_PRICE + ") VALUES ('Banana Choc Cake', 55, 500);");
db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE
+ ", " + COL_CAKE_PRICE + ") VALUES ('Banoffee', 75, 700);");
db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE
+ ", " + COL_CAKE_PRICE + ") VALUES ('Cheese Cake', 85, 800);");
db.execSQL("INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_PIECE_PRICE
+ ", " + COL_CAKE_PRICE + ") VALUES ('Tiramisu', 85, 800);");
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
ใน Activity ที่ใช้งานฐานข้อมูลก็จะมีการเพิ่มคำสั่งก๊อปไฟล์ฐานข้อมูลเข้าไปด้วย (คืออยากก๊อปไฟล์ตอนไหนก็ใส่ตอนนั้นน่ะแหละ)
MainActivity.java
package com.akexorcist.exportdatabase;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyDbHelper helper = new MyDbHelper(this);
helper.getWritableDatabase();
exportDatabaseFile(this, "bakery_store");
}
public boolean exportDatabaseFile(Context context, String dbName) {
try {
File dbFile = context.getDatabasePath(dbName);
File exportFile = new File(Environment.getExternalStorageDirectory() + "/" + dbName);
FileInputStream fileInputStream = new FileInputStream(dbFile);
FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
FileChannel fileInputChannel = fileInputStream.getChannel();
FileChannel fileOutputChannel = fileOutputStream.getChannel();
fileInputChannel.transferTo(0, fileInputChannel.size(), fileOutputChannel);
fileInputStream.close();
fileOutputStream.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
จากนั้นก็เปิดแอพซะ แล้วให้คำสั่งดังกล่าวมันทำงาน แล้วค่อยไปเปิดไฟล์ในเครื่องเพื่อโอนลงคอมพิวเตอร์
สรุปสั้นๆ - ใส่โค๊ดให้แอพมันก๊อปไฟล์ฐานข้อมูลของมันเองไว้ที่ External Storage จะได้ก๊อปลงคอมพิวเตอร์ได้ (ต้องแอพที่เป็นเจ้าของโฟลเดอร์เท่านั้น ไม่สามารถไปก๊อปของแอพตัวอื่นได้)
เพียงเท่านี้ก็ได้ไฟล์ฐานข้อมูลมาเปิดดูบนคอมพิวเตอร์แล้ว
สำหรับผู้ที่หลงเข้ามาอ่านคนใดต้องการไฟล์ตัวอย่างสามารถดาวน์โหลดได้จาก
• Sleeping For Less
• Google Drive