您好我正在尝试在Android Studio中创建一个简单的登录应用程序,其中从SQLite表中读取用户数据。到目前为止,我已经创建了我的表,并且从头到尾完全遵循了这个tutorial。但是我一直找不到表或表损坏错误。这是我的代码:
package com.example.b00694394.granshataxicompany2;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
private static final String DATABASE_NAME = "gransha.db";
private static final int DATABASE_VERSION = 1;
private final Context context;
SQLiteDatabase db;
private static final String DATABASE_PATH = "/data/data/com.example.b00694394.granshataxicompany2/databases/";
private final String DRIVERS_TABLE ="Drivers";
public Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
createDb();
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public void createDb() {
boolean dbExist = checkDbExist();
if (!dbExist){
this.getReadableDatabase();
copyDatabase();
}
}
private boolean checkDbExist() {
SQLiteDatabase sqLiteDatabase = null;
try {
String path = DATABASE_PATH + DATABASE_NAME;
sqLiteDatabase = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
} catch (Exception ex){
}
if (sqLiteDatabase != null) {
sqLiteDatabase.close();
return true;
}
return false;
}
private void copyDatabase() {
try {
InputStream inputStream = context.getAssets().open(DATABASE_NAME);
String outFileName = DATABASE_PATH + DATABASE_NAME;
OutputStream outputStream = new FileOutputStream(outFileName);
byte[] b = new byte[1024];
int lenght;
while ((lenght = inputStream.read(b)) > 0 ){
outputStream.write(b, 0, lenght);
}
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private SQLiteDatabase openDatabase() {
String path = DATABASE_PATH + DATABASE_NAME;
db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);
return db;
}
public void close(){
if(db !=null){
db.close();
}
}
public boolean checkUserExist (String dNum, String dPass){
String[] columns = {"Driver_Number"};
db = openDatabase();
String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass;
String[] selectionArgs = {dNum, dPass};
Cursor cursor = db.query(DRIVERS_TABLE, columns, selection, selectionArgs, null, null, null);
int count = cursor.getCount();
cursor.close();
close();
if (count > 0) {
return true;
} else {
return false;
}
}
}
这是运行时错误日志:
E/SQLiteLog: (26) file is encrypted or is not a database
E/DefaultDatabaseErrorHandler: Corruption reported by sqlite on database: /data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db
E/DefaultDatabaseErrorHandler: deleting the database file: /data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db
E/SQLiteLog: (14) cannot open file at line 35803 of [605907e73a]
(14) os_unix.c:35803: (2) open(/data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db) -
E/SQLiteDatabase: Failed to open database '/data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:210)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:194)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:493)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:200)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:192)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:864)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:852)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:750)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:699)
at com.example.b00694394.granshataxicompany2.Database.openDatabase(Database.java:100)
at com.example.b00694394.granshataxicompany2.Database.checkUserExist(Database.java:113)
at com.example.b00694394.granshataxicompany2.loginPage$1.onClick(loginPage.java:40)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.b00694394.granshataxicompany2, PID: 11343
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:210)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:194)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:493)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:200)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:192)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:864)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:852)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:750)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:699)
at com.example.b00694394.granshataxicompany2.Database.openDatabase(Database.java:100)
at com.example.b00694394.granshataxicompany2.Database.checkUserExist(Database.java:113)
at com.example.b00694394.granshataxicompany2.loginPage$1.onClick(loginPage.java:40)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Application terminated.
非常感谢任何帮助。谢谢!
答案 0 :(得分:1)
您的问题是文件 gransha.db 不是有效的数据库文件
E/SQLiteLog: (26) file is encrypted or is not a database
然后发生的是,SQLiteDatabase OpenOrCreate方法(由SQLiteOpenHelper的子类调用)删除该文件并创建一个空数据库,因此为什么在获取损坏的数据库后运行时会得到未找到的表。
修复是为了确保在将数据库文件复制到assets文件夹之前使用SQLite工具(例如,针对SQLite的Db浏览器,DBeaver,SQLite Manager ....)创建和保存数据库文件,然后删除应用程序的数据(删除空的但有效的数据库)并重新运行应用程序。
实际测试你的代码时你遇到了checkUserExist方法的问题,因为它由于字符串没有用引号括起来而失败,所以值test和123虽然是列名(但是测试不是列名而失败) )。
所以而不是: -
String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass;
您需要使用: -
String selection = '"Driver_Number = "' + dNum + " and Driver_Password = '"+ dPass + "'";
但是,由于您已经正确设置selectionArgs
,因此应使用以下内容: -
public boolean checkUserExist (String dNum, String dPass){
String[] columns = {"Driver_Number"};
db = openDatabase();
//String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass; <<<< commented out
String selection = "Driver_Number=? AND Driver_Password=?"; //<<<< ?'s replaced by values in selectionArgs
String[] selectionArgs = {dNum, dPass};
Cursor cursor = db.query(DRIVERS_TABLE, columns, selection, selectionArgs, null, null, null);
int count = cursor.getCount();
cursor.close();
close();
if (count > 0) {
return true;
} else {
return false;
}
}
这是推荐的方法(你不会让SQL注入警察跳进来)。那是你的代码吗?在字符串中,根据args中的值(代表您逃避)按顺序替换。即第一个?将被第一个arg取代,第二个?由第二个arg ..........
我还建议不要使用硬编码的DB Path: -
private static final String DATABASE_PATH = "/data/data/com.example.b00694394.granshataxicompany2/databases/";
但是用
替换上面的内容 private static DATABASE_PATH;
将构造函数更改为: -
public Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
DATABASE_PATH = context.getDatabasePath(DATABASE_NAME).getParent()+File.separator;
createDb();
}
另一个建议是简化checkDBExists,它还具有在无法打开数据库时不产生堆栈跟踪的好处。
因此,检查文件是否存在,而不是checkDBExists,而不是checkDBExists: -
private boolean altCheckDBExist() {
File chkdb = new File(context.getDatabasePath(DATABASE_NAME).getPath());
return chkdb.exists();
}
所以你使用以下方法来使用它: -
public void createDb() {
/*
boolean dbExist = checkDbExist();
if (!dbExist){
this.getReadableDatabase();
copyDatabase();
}
*/
if (!altCheckDBExist()) {
this.getWritableDatabase();
copyDatabase();
}
}
我下载了Navicat免费试用版(Navicat for SQLite3),创建了数据库,添加了表格和数据,保存了它(关闭连接),将文件复制到资源文件夹,运行App(删除App&#39后) ; s数据),它的工作原理。
因此可以使用Navicat,更多的是它是如何使用的。