sqliteLog 14:无法在行打开文件
sqliteLog 14: cannot open file at line
我不知道我的错误在哪里。当数据库不存在且我的 checkDatabase 方法 returns 为 false 或我的数据库时,我试图将 lyrics.db
文件存储在我的 DB_PATH
中已过时。
但是,我得到以下信息:-
E/SQLiteLog: (14) cannot open file at line 36356 of [605907e73a]
(14) os_unix.c:36356: (2) open(/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db) -
(1) Process ts_mobile_16862 : Pid (12455) Uid (10196) Euid (10196) Gid (10196) Egid (10196)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db" due to error (2)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases" due to error (2)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862" due to error (2)
(1) Stat of /data/user/0/id.ac.umn.project_uts_mobile_16862 : st_mode(40700) st_uid(10196) st_gid(10196) st_ino(265643)
(1) Stat of /data/user/0 : st_mode(40771) st_uid(1000) st_gid(1000) st_ino(262147)
(1) Stat of /data/user : st_mode(40711) st_uid(1000) st_gid(1000) st_ino(196619)
(1) Stat of /data : st_mode(40771) st_uid(1000) st_gid(1000) st_ino(2)
E/SQLiteDatabase: Failed to open database '/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 1294): Could not open database
#################################################################
Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
Caused By : Specified directory or database file does not exist.
(unknown error (code 1294): Could not open database)
#################################################################
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:272)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:213)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:701)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:272)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:239)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:1276)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:1231)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:915)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:864)
at id.ac.umn.project_uts_mobile_16862.DbHelper.checkDatabase(DbHelper.java:50)
at id.ac.umn.project_uts_mobile_16862.DbHelper.createDB(DbHelper.java:85)
at id.ac.umn.project_uts_mobile_16862.show_lyrics.onCreate(show_lyrics.java:22)
at android.app.Activity.performCreate(Activity.java:7258)
at android.app.Activity.performCreate(Activity.java:7249)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1222)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3059)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1724)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
这是我加载数据库的代码
public class DbHelper extends SQLiteOpenHelper {
private static String DB_PATH = "";
private static String DB_NAME = "lyrics.db";
private SQLiteDatabase vDatabase;
private Context vContext = null;
public DbHelper(Context context) {
super(context, DB_NAME, null, 1);
if( Build.VERSION.SDK_INT >= 17)
DB_PATH = context.getFilesDir().getPath()+context.getPackageName()+"/databases/";
else
DB_PATH = context.getApplicationInfo().dataDir+"/databases/";
this.vContext = context;
}
@Override
public synchronized void close() {
if( vDatabase != null ) {
vDatabase.close();
}
super.close();
}
private boolean checkDatabase() {
SQLiteDatabase dbTemp = null;
try{
String path = DB_PATH + DB_NAME;
dbTemp = SQLiteDatabase.openDatabase(path, null, OPEN_READWRITE);
} catch ( SQLiteException e) { }
if (dbTemp != null ) {
dbTemp.close();
}
return dbTemp != null;
}
public void copyDB() throws SQLiteException{
try {
InputStream myInput = vContext.getAssets().open(DB_NAME);
String outputFileName = DB_PATH + DB_NAME;
Log.d("LIFECYCLE", outputFileName);
OutputStream myOutput = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while( (length=myInput.read(buffer)) > 0 ){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
public void openDB() {
String path = DB_PATH + DB_NAME;
vDatabase = SQLiteDatabase.openDatabase(path, null, OPEN_READWRITE);
}
public void createDB() {
boolean dbExist = checkDatabase();
if ( dbExist ){
}
else {
this.getReadableDatabase();
copyDB();
}
}
public List<Lyric> getAllSong(){
List<Lyric> temp = new ArrayList<>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor;
try{
cursor = db.rawQuery( "SELECT * FROM lyrics" , null);
if( cursor == null) return null;
cursor.moveToFirst();
do {
Lyric lyric = new Lyric(
cursor.getString(cursor.getColumnIndex("index")),
cursor.getString(cursor.getColumnIndex("song")),
cursor.getString(cursor.getColumnIndex("year")),
cursor.getString(cursor.getColumnIndex("artist")),
cursor.getString(cursor.getColumnIndex("genre")),
cursor.getString(cursor.getColumnIndex("lyrics"))
);
temp.add(lyric);
} while (cursor.moveToNext());
cursor.close();
} catch ( Exception e){ }
db.close();
return temp;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
我已经尝试调试这段代码将近 15 个小时,甚至没有得到任何线索,我的错误在哪里。
如何检查该路径是否存在?以及如果不存在如何创建目录/路径?
I've already trying to debug this code for almost 15 hours, and even
don't get a single clue, where are my mistakes.
您的问题是当您尝试在 checkDatabase 方法中打开数据库时 databases 目录不存在。
线索在这里:-
Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
Caused By : Specified directory or database file does not exist.
(unknown error (code 1294): Could not open database)
路径通常是data/data/your_package/databases/your_database_file
data/data 将存在,因为它是 android 的一部分。
package 子目录将作为安装包的一部分存在。
databases 目录最初并不存在,使用 SQLiteOpenHelper 的子class 将在创建数据库时创建 databases 文件夹,因此您看到尝试通过这样的帮助程序打开数据库,只是为了创建数据库目录。但是,这可能会有问题,因为从 Android 默认情况下使用 SQLite 上的 Pie WAL 模式,除非在复制数据库之前删除 -shm 和 -wal 文件,否则会创建一个空数据库(- wal/-shm 文件不会 belong/correlate 到复制的数据库,因此数据库文件是 deleted/emptied).
我建议不要尝试打开数据库,而是检查 File 是否存在,如果不存在则检查文件的父文件是否存在(数据库目录),如果不存在则使用 mkdirs 方法创建目录。
以下是执行上述所有检查的示例方法:-
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(myContext.getDatabasePath(DB_NAME).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath());
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exist then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
- 请注意,上面使用了推荐的 getDatabasePath,因此除了数据库名称外,无需硬编码任何其他内容(您可能希望在整个代码中采用它)。
分步指南。
1。使用适当的 SQL 站点管理工具创建数据库,并在 table lyrics 中填充所需数据。确保数据库已保存。
- 在本例中使用了 NaviCat,下面的 SQL 用于创建和填充歌词 table。
:-
CREATE TABLE IF NOT EXISTS lyrics (
id INTEGER PRIMARY KEY,
song TEXT,
year TEXT,
artist TEXT,
genre TEXT,
lyrics TEXT
);
INSERT INTO lyrics (song, year, artist, genre, lyrics) VALUES
('song1','1970','Fred','Rock','Rock rock rock'),
('song2','1980','Mary','Pop','Pop pop pop'),
('song3','1960','Sue','Folk','Folk folk folk');
- 注意 index 是一个关键字,因此除非将其括起来,否则它不是有效的列名,因此使用 id 代替索引.
2。文件保存为lyrics.db复制到项目的assets文件夹中
3。 DbHelper.java(各种修改)
public class DbHelper extends SQLiteOpenHelper {
private static String DB_NAME = "lyrics.db";
private SQLiteDatabase vDatabase;
private Context vContext;
public DbHelper(Context context) {
super(context, DB_NAME, null, 1);
this.vContext = context;
// Copy the DB if need be when instantiating the DbHelper
if (!checkDataBase()) {
copyDB();
}
vDatabase = this.getWritableDatabase(); //Get the database when instantiating
}
/**
* No need for build version check as getDataBasePath works for all versions
* No need for open and close of Database, just open it once for the lifetime (more efficient)
*/
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(vContext.getDatabasePath(DB_NAME).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath());
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exist then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
public void copyDB() throws SQLiteException{
try {
InputStream myInput = vContext.getAssets().open(DB_NAME);
String outputFileName = vContext.getDatabasePath(DB_NAME).getPath(); //<<<<<<<<<< changed
Log.d("LIFECYCLE", outputFileName);
OutputStream myOutput = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while( (length=myInput.read(buffer)) > 0 ){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
public List<Lyric> getAllSong(){
List<Lyric> temp = new ArrayList<>();
Cursor cursor = vDatabase.query("lyrics",null,null,null,null,null,null);
//Cursor cursor = db.rawQuery( "SELECT * FROM lyrics" , null); // used query method generally preferred to rawQuery
//if( cursor == null) return null; // Cursor will not be null may be empty
//cursor.moveToFirst(); // changed to use simpler loop
while (cursor.moveToNext()) {
Lyric lyric = new Lyric(
//cursor.getString(cursor.getColumnIndex("index")), //<<<<<<< changed due to column name change
cursor.getString(cursor.getColumnIndex("id")),
cursor.getString(cursor.getColumnIndex("song")),
cursor.getString(cursor.getColumnIndex("year")),
cursor.getString(cursor.getColumnIndex("artist")),
cursor.getString(cursor.getColumnIndex("genre")),
cursor.getString(cursor.getColumnIndex("lyrics"))
);
temp.add(lyric);
}
cursor.close();
//db.close(); // inefficient to keep on opening and closing db
return temp;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- 查看评论重新修改
4。卸载现有应用或删除应用数据(重要)
5。测试一下。
下面是一个 activity 来测试上面的内容。
public class MainActivity extends AppCompatActivity {
DbHelper vDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vDBHlpr = new DbHelper(this);
List<Lyric> mylyricslist = vDBHlpr.getAllSong();
for (Lyric l: mylyricslist) {
Log.d("LYRICFROMDB","Song is " + l.getSong() + " Year is " + l.getYear() + " Artist is " + l.getArtist() + " Genre is " + l.getGenre() + " Lyrics are " + l.getLyrics());
}
}
}
日志应该包括(第一个运行):-
03-17 19:42:11.067 16057-16057/? D/DBPATH: DB Path is /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:42:11.067 16057-16057/? D/LIFECYCLE: /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song1 Year is 1970 Artist is Fred Genre is Rock Lyrics are Rock rock rock
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song2 Year is 1980 Artist is Mary Genre is Pop Lyrics are Pop pop pop
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song3 Year is 1960 Artist is Sue Genre is Folk Lyrics are Folk folk folk
或后续 运行s :-
03-17 19:49:11.275 16136-16136/? D/DBPATH: DB Path is /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song1 Year is 1970 Artist is Fred Genre is Rock Lyrics are Rock rock rock
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song2 Year is 1980 Artist is Mary Genre is Pop Lyrics are Pop pop pop
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song3 Year is 1960 Artist is Sue Genre is Folk Lyrics are Folk folk folk
- 注意 运行 两次,以便检查复制过程和现有数据库的处理。
以上是在模拟器上测试的 运行ning Android Lollipop 和 Pie
我不知道我的错误在哪里。当数据库不存在且我的 checkDatabase 方法 returns 为 false 或我的数据库时,我试图将 lyrics.db
文件存储在我的 DB_PATH
中已过时。
但是,我得到以下信息:-
E/SQLiteLog: (14) cannot open file at line 36356 of [605907e73a]
(14) os_unix.c:36356: (2) open(/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db) -
(1) Process ts_mobile_16862 : Pid (12455) Uid (10196) Euid (10196) Gid (10196) Egid (10196)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db" due to error (2)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases" due to error (2)
(1) osStat failed "/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862" due to error (2)
(1) Stat of /data/user/0/id.ac.umn.project_uts_mobile_16862 : st_mode(40700) st_uid(10196) st_gid(10196) st_ino(265643)
(1) Stat of /data/user/0 : st_mode(40771) st_uid(1000) st_gid(1000) st_ino(262147)
(1) Stat of /data/user : st_mode(40711) st_uid(1000) st_gid(1000) st_ino(196619)
(1) Stat of /data : st_mode(40771) st_uid(1000) st_gid(1000) st_ino(2)
E/SQLiteDatabase: Failed to open database '/data/user/0/id.ac.umn.project_uts_mobile_16862/filesid.ac.umn.project_uts_mobile_16862/databases/lyrics.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 1294): Could not open database
#################################################################
Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
Caused By : Specified directory or database file does not exist.
(unknown error (code 1294): Could not open database)
#################################################################
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:272)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:213)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:701)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:272)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:239)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:1276)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:1231)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:915)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:864)
at id.ac.umn.project_uts_mobile_16862.DbHelper.checkDatabase(DbHelper.java:50)
at id.ac.umn.project_uts_mobile_16862.DbHelper.createDB(DbHelper.java:85)
at id.ac.umn.project_uts_mobile_16862.show_lyrics.onCreate(show_lyrics.java:22)
at android.app.Activity.performCreate(Activity.java:7258)
at android.app.Activity.performCreate(Activity.java:7249)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1222)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3059)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1724)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
这是我加载数据库的代码
public class DbHelper extends SQLiteOpenHelper {
private static String DB_PATH = "";
private static String DB_NAME = "lyrics.db";
private SQLiteDatabase vDatabase;
private Context vContext = null;
public DbHelper(Context context) {
super(context, DB_NAME, null, 1);
if( Build.VERSION.SDK_INT >= 17)
DB_PATH = context.getFilesDir().getPath()+context.getPackageName()+"/databases/";
else
DB_PATH = context.getApplicationInfo().dataDir+"/databases/";
this.vContext = context;
}
@Override
public synchronized void close() {
if( vDatabase != null ) {
vDatabase.close();
}
super.close();
}
private boolean checkDatabase() {
SQLiteDatabase dbTemp = null;
try{
String path = DB_PATH + DB_NAME;
dbTemp = SQLiteDatabase.openDatabase(path, null, OPEN_READWRITE);
} catch ( SQLiteException e) { }
if (dbTemp != null ) {
dbTemp.close();
}
return dbTemp != null;
}
public void copyDB() throws SQLiteException{
try {
InputStream myInput = vContext.getAssets().open(DB_NAME);
String outputFileName = DB_PATH + DB_NAME;
Log.d("LIFECYCLE", outputFileName);
OutputStream myOutput = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while( (length=myInput.read(buffer)) > 0 ){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
public void openDB() {
String path = DB_PATH + DB_NAME;
vDatabase = SQLiteDatabase.openDatabase(path, null, OPEN_READWRITE);
}
public void createDB() {
boolean dbExist = checkDatabase();
if ( dbExist ){
}
else {
this.getReadableDatabase();
copyDB();
}
}
public List<Lyric> getAllSong(){
List<Lyric> temp = new ArrayList<>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor;
try{
cursor = db.rawQuery( "SELECT * FROM lyrics" , null);
if( cursor == null) return null;
cursor.moveToFirst();
do {
Lyric lyric = new Lyric(
cursor.getString(cursor.getColumnIndex("index")),
cursor.getString(cursor.getColumnIndex("song")),
cursor.getString(cursor.getColumnIndex("year")),
cursor.getString(cursor.getColumnIndex("artist")),
cursor.getString(cursor.getColumnIndex("genre")),
cursor.getString(cursor.getColumnIndex("lyrics"))
);
temp.add(lyric);
} while (cursor.moveToNext());
cursor.close();
} catch ( Exception e){ }
db.close();
return temp;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
我已经尝试调试这段代码将近 15 个小时,甚至没有得到任何线索,我的错误在哪里。
如何检查该路径是否存在?以及如果不存在如何创建目录/路径?
I've already trying to debug this code for almost 15 hours, and even don't get a single clue, where are my mistakes.
您的问题是当您尝试在 checkDatabase 方法中打开数据库时 databases 目录不存在。
线索在这里:-
Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
Caused By : Specified directory or database file does not exist.
(unknown error (code 1294): Could not open database)
路径通常是data/data/your_package/databases/your_database_file
data/data 将存在,因为它是 android 的一部分。
package 子目录将作为安装包的一部分存在。
databases 目录最初并不存在,使用 SQLiteOpenHelper 的子class 将在创建数据库时创建 databases 文件夹,因此您看到尝试通过这样的帮助程序打开数据库,只是为了创建数据库目录。但是,这可能会有问题,因为从 Android 默认情况下使用 SQLite 上的 Pie WAL 模式,除非在复制数据库之前删除 -shm 和 -wal 文件,否则会创建一个空数据库(- wal/-shm 文件不会 belong/correlate 到复制的数据库,因此数据库文件是 deleted/emptied).
我建议不要尝试打开数据库,而是检查 File 是否存在,如果不存在则检查文件的父文件是否存在(数据库目录),如果不存在则使用 mkdirs 方法创建目录。
以下是执行上述所有检查的示例方法:-
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(myContext.getDatabasePath(DB_NAME).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath());
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exist then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
- 请注意,上面使用了推荐的 getDatabasePath,因此除了数据库名称外,无需硬编码任何其他内容(您可能希望在整个代码中采用它)。
分步指南。
1。使用适当的 SQL 站点管理工具创建数据库,并在 table lyrics 中填充所需数据。确保数据库已保存。
- 在本例中使用了 NaviCat,下面的 SQL 用于创建和填充歌词 table。
:-
CREATE TABLE IF NOT EXISTS lyrics (
id INTEGER PRIMARY KEY,
song TEXT,
year TEXT,
artist TEXT,
genre TEXT,
lyrics TEXT
);
INSERT INTO lyrics (song, year, artist, genre, lyrics) VALUES
('song1','1970','Fred','Rock','Rock rock rock'),
('song2','1980','Mary','Pop','Pop pop pop'),
('song3','1960','Sue','Folk','Folk folk folk');
- 注意 index 是一个关键字,因此除非将其括起来,否则它不是有效的列名,因此使用 id 代替索引.
2。文件保存为lyrics.db复制到项目的assets文件夹中
3。 DbHelper.java(各种修改)
public class DbHelper extends SQLiteOpenHelper {
private static String DB_NAME = "lyrics.db";
private SQLiteDatabase vDatabase;
private Context vContext;
public DbHelper(Context context) {
super(context, DB_NAME, null, 1);
this.vContext = context;
// Copy the DB if need be when instantiating the DbHelper
if (!checkDataBase()) {
copyDB();
}
vDatabase = this.getWritableDatabase(); //Get the database when instantiating
}
/**
* No need for build version check as getDataBasePath works for all versions
* No need for open and close of Database, just open it once for the lifetime (more efficient)
*/
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(vContext.getDatabasePath(DB_NAME).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath());
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exist then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
public void copyDB() throws SQLiteException{
try {
InputStream myInput = vContext.getAssets().open(DB_NAME);
String outputFileName = vContext.getDatabasePath(DB_NAME).getPath(); //<<<<<<<<<< changed
Log.d("LIFECYCLE", outputFileName);
OutputStream myOutput = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while( (length=myInput.read(buffer)) > 0 ){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch ( IOException e) {
e.printStackTrace();
}
}
public List<Lyric> getAllSong(){
List<Lyric> temp = new ArrayList<>();
Cursor cursor = vDatabase.query("lyrics",null,null,null,null,null,null);
//Cursor cursor = db.rawQuery( "SELECT * FROM lyrics" , null); // used query method generally preferred to rawQuery
//if( cursor == null) return null; // Cursor will not be null may be empty
//cursor.moveToFirst(); // changed to use simpler loop
while (cursor.moveToNext()) {
Lyric lyric = new Lyric(
//cursor.getString(cursor.getColumnIndex("index")), //<<<<<<< changed due to column name change
cursor.getString(cursor.getColumnIndex("id")),
cursor.getString(cursor.getColumnIndex("song")),
cursor.getString(cursor.getColumnIndex("year")),
cursor.getString(cursor.getColumnIndex("artist")),
cursor.getString(cursor.getColumnIndex("genre")),
cursor.getString(cursor.getColumnIndex("lyrics"))
);
temp.add(lyric);
}
cursor.close();
//db.close(); // inefficient to keep on opening and closing db
return temp;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- 查看评论重新修改
4。卸载现有应用或删除应用数据(重要)
5。测试一下。
下面是一个 activity 来测试上面的内容。
public class MainActivity extends AppCompatActivity {
DbHelper vDBHlpr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vDBHlpr = new DbHelper(this);
List<Lyric> mylyricslist = vDBHlpr.getAllSong();
for (Lyric l: mylyricslist) {
Log.d("LYRICFROMDB","Song is " + l.getSong() + " Year is " + l.getYear() + " Artist is " + l.getArtist() + " Genre is " + l.getGenre() + " Lyrics are " + l.getLyrics());
}
}
}
日志应该包括(第一个运行):-
03-17 19:42:11.067 16057-16057/? D/DBPATH: DB Path is /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:42:11.067 16057-16057/? D/LIFECYCLE: /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song1 Year is 1970 Artist is Fred Genre is Rock Lyrics are Rock rock rock
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song2 Year is 1980 Artist is Mary Genre is Pop Lyrics are Pop pop pop
03-17 19:42:11.086 16057-16057/? D/LYRICFROMDB: Song is song3 Year is 1960 Artist is Sue Genre is Folk Lyrics are Folk folk folk
或后续 运行s :-
03-17 19:49:11.275 16136-16136/? D/DBPATH: DB Path is /data/data/com.example.so55199382lyrics/databases/lyrics.db
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song1 Year is 1970 Artist is Fred Genre is Rock Lyrics are Rock rock rock
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song2 Year is 1980 Artist is Mary Genre is Pop Lyrics are Pop pop pop
03-17 19:49:11.279 16136-16136/? D/LYRICFROMDB: Song is song3 Year is 1960 Artist is Sue Genre is Folk Lyrics are Folk folk folk
- 注意 运行 两次,以便检查复制过程和现有数据库的处理。
以上是在模拟器上测试的 运行ning Android Lollipop 和 Pie