sqliteLog 14: невозможно открыть файл в строке - PullRequest
0 голосов
/ 16 марта 2019

Я не знаю, где мои ошибки.Я пытаюсь сохранить файл lyrics.db в моем DB_PATH, когда база данных не существует, а мой метод checkDatabase возвращает значение false или моя БД устарела.

Однако яполучить следующее: -

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 часов, и даже не получаюединственная подсказка, где мои ошибки.

как проверить, существует ли этот путь?и как сделать каталог / путь, если он не существует?

Ответы [ 2 ]

1 голос
/ 17 марта 2019

Пошаговое руководство.

1.Создайте базу данных с помощью соответствующего инструмента управления SQLite с таблицей lyrics , заполненной необходимыми данными.Обеспечение сохранения базы данных.

  • В этом случае использовался NaviCat, а для создания и заполнения таблицы текстов песен использовался следующий SQL.

: -

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 и скопирован в папку ресурсов проекта.

enter image description here

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.Проверьте это.

Ниже приведено действие, которое будет проверять выше.

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

или дляпоследующие запуски: -

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
  • Примечание запускается дважды, поэтому вы проверяете как процесс копирования, так и обработку существующей базы данных.

Выше было проверено на эмуляторах под управлением AndroidЛеденец и пирог

1 голос
/ 16 марта 2019

Я уже пытаюсь отлаживать этот код почти 15 часов, и даже не понимаю, где мои ошибки.

Ваша проблема в том, что каталог database не существует при попытке открыть базу данных в методе checkDatabase .

Ключ здесь: -

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 / database / your_database_file

data / data будет существовать как часть Android.

Подкаталог пакета будет существовать как часть установки пакета.

Каталог database изначально не существует, при использовании подкласса SQLiteOpenHelper при создании базы данных создаст папку database и, следовательно, почему вы видите попытки открыть базы данных через такого помощника, просто чтобы создать каталог баз данных. Однако это может быть проблематично, так как в Android Pie на SQLite используется режим WAL по умолчанию, который, если файлы -shm и -wal не будут удалены перед копированием базы данных, приведет к созданию пустой базы данных (-wal / -shm файлы не принадлежат скопированной базе данных / не соответствуют ей, поэтому файл базы данных удален / очищен).

Я бы посоветовал вместо того, чтобы пытаться открыть базу данных, которую вы проверяете, чтобы проверить, существует ли Файл , а если нет, то проверить, существует ли родительский файл файла (каталог баз данных), и если это не так. не существует метода 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, поэтому нет необходимости жестко кодировать что-либо, кроме имени базы данных (вы можете захотеть применить это в своем коде).
...