Unity的安装数据库(SQLite)
我看过太多教程列表,他们都推荐相同的东西。 但是,他们没有帮助解决我的问题。
我试图在我的项目中包含一个SQLite数据库,当构建PC,MAC和Linux Standalone(在Windows机器上测试)时,数据库按预期工作。 在Android设备上进行测试时,出现以下错误。
E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/TBLDatabase.db" at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler+c__Iterator2.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0
我认为对connectionString进行修改应该很简单,但这并没有解决我的问题。 这是我到目前为止:
if (Application.platform != RuntimePlatform.Android) { // The name of the db. tblDatabase = "URI=file:" + Application.dataPath + "/TBLDatabase.db"; //returns the complete path to database file exist. } else { tblDatabase = Application.persistentDataPath + "/TBLDatabase.db"; if (!File.Exists(tblDatabase)) { // if it doesn't -> Debug.LogWarning("File \"" + tblDatabase + "\" does not exist. Attempting to create from \"" + Application.dataPath + "!/assets/" + "TBLDatabase.db"); // open StreamingAssets directory and load the db -> // #if UNITY_ANDROID var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + "TBLDatabase.db"); // this is the path to your StreamingAssets in android while (!loadDb.isDone) { } // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check // then save to Application.persistentDataPath File.WriteAllBytes(tblDatabase, loadDb.bytes); } } //open db connection var connection = new SqliteConnection(tblDatabase); connection.Open(); var command = connection.CreateCommand();
我已经使用了adb shell并从我的Android设备中提取了数据库,所有内容都符合预期(数据库确实存在并且它不是空的)。
我相信我有所有相关的DLL文件,但如果有人能给我一些指导我会很感激。
************************************************** *编辑**********************************************
我根据给出的建议做了以下改动。
我现在调用以下方法来启动我的连接并处理数据库请求StartCoroutine(RunDbCode(dbFileName, jsonStudentID, jsonIndiNames, jsonIndiStudentNumbers));
然后我有以下方法:
IEnumerator RunDbCode(string fileName, List jsonStudentID, List jsonIndiNames, List jsonIndiStudentNumbers) { //Where to copy the db to string dbDestination = Path.Combine(Application.persistentDataPath, "data"); dbDestination = Path.Combine(dbDestination, fileName); //Check if the File do not exist then copy it if (!File.Exists(dbDestination)) { //Where the db file is at string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName); byte[] result; //Read the File from streamingAssets. Use WWW for Android if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///")) { WWW www = new WWW(dbStreamingAsset); yield return www; result = www.bytes; } else { result = File.ReadAllBytes(dbStreamingAsset); } Debug.Log("Loaded db file"); //Create Directory if it does not exist if (!Directory.Exists(Path.GetDirectoryName(dbDestination))) { Directory.CreateDirectory(Path.GetDirectoryName(dbDestination)); } //Copy the data to the persistentDataPath where the database API can freely access the file File.WriteAllBytes(dbDestination, result); Debug.Log("Copied db file"); } //Now you can do the database operation //open db connection var connection = new SqliteConnection(dbDestination); connection.Open(); var command = connection.CreateCommand(); // Drop the table if it already exists. command.CommandText = "DROP TABLE IF EXISTS existing_individual;"; command.ExecuteNonQuery(); var sql = "CREATE TABLE existing_individual (studentID VARCHAR(23), fullName VARCHAR(50), studentNumber VARCHAR(20))"; command.CommandText = sql; command.ExecuteNonQuery(); //Inserting the exisiting student names returned, into the SQLite DB int count = 0; foreach (var individuals in jsonStudentID) { //looping through the existing students registered for the individual quiz - below has been written to avoid SQL injection sql = "INSERT INTO existing_individual (studentID, fullName, studentNumber) VALUES (@jsonStudentID, @jsonIndiNames, @jsonIndiStudentNumbers)"; command.Parameters.AddWithValue("@jsonStudentID", jsonStudentID[count]); command.Parameters.AddWithValue("@jsonIndiNames", jsonIndiNames[count]); command.Parameters.AddWithValue("@jsonIndiStudentNumbers", jsonIndiStudentNumbers[count]); command.CommandText = sql; command.ExecuteNonQuery(); count++; } //close the connection command.Dispose(); command = null; connection.Close(); connection = null; }
但是,我仍然收到以下错误:
06-08 15:26:56.498 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/data/TBLDatabase.db" at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler+c__Iterator3.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0 UnityEngine.MonoBehaviour:StartCoroutineManaged2(IEnumerator) UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) c__Iterator2:MoveNext() UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr) (Filename: Line: -1) 06-08 15:26:56.502 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "URI" at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler.CreateIndiButton () [0x00000] in :0 at UIHandler+c__Iterator2.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0
我还将我的数据库添加到’StreamingAssets’文件夹中,如下图所示:
下面还显示了我的插件文件夹的图像,其中包含我的dll文件。
关于此主题的大多数教程都已过时。
看了一下代码,发现了一些问题,但我不知道这些是你得到这个错误的原因。 WWW
应该在协程函数中使用,以便您可以通过在while
循环中添加yield return null
来产生或等待loadDb.isDone
完成。 你也可以自己产生WWW
请求,这就是我将在我的答案中使用的方法。
另外, jar:file://" + Application.dataPath
是一个旧代码。使用Application.streamingAssetsPath
。此外,你不需要"URI=file:" + Application.dataPath
。只需使用Application.persistentDataPath
。 。
我将简单介绍一下如何进行设置。
设置MANAGED代码部分:
1.转到Unity安装路径
\Editor\Data\Mono\lib\mono\2.0
复制以下文件:
-
I18N.MidEast.dll
-
I18N.Other.dll
-
I18N.Rare.dll
-
I18N.West.dll
-
Mono.Data.Sqlite.dll
-
Mono.Data.SqliteClient.dll
-
System.Data.dll
到项目的
路径。
这将允许您从Mono.Data.Sqlite
命名空间编译API而不会出现任何错误。
设置UNMANAGED代码部分:
在此步骤中,您将需要获取本机Sqlite库。 您可以获取源代码 ,构建它并使用它或使用已经预编译的binray。
1.获取Windows的本机库
从此处下载预编译的sqlite3.dll
for Windows 64位,并将其放在
路径中。
如果使用Windows 32位,则从此处获取sqlite3.dll
版本并将其放在
路径中。
2.获取Android的本机库
从此处下载Android ARM处理器的预编译libsqlite3.so
,并将其放在
路径中。
从此处下载libsqlite3.so
于Android Intel x86处理器的预编译libsqlite3.so
,并将其放在
路径中。
这涵盖了Android设备上使用的大多数处理器 。
3.获取UWP的本机库
A.下载WSA文件夹,然后将WSA文件夹放在
路径中。 该文件夹包含本机部分。
B.在
路径中创建名为“mcs.rsp”和“csc.rsp”的 2个文件。
C.在“mcs.rsp”和“csc.rsp”文件中添加以下内容:
-r:I18N.MidEast.dll -r:I18N.Other.dll -r:I18N.Rare.dll -r:I18N.West.dll -r:Mono.Data.Sqlite.dll -r:Mono.Data.SqliteClient.dll -r:System.Data.dll
D.在构建UWP时,您必须将托管dll移动到项目的根文件夹。 所以,将I18N.MidEast.dll
, I18N.Other.dll
, I18N.Rare.dll
, I18N.West.dll
, Mono.Data.Sqlite.dll
, Mono.Data.SqliteClient.dll
, System.Data.dll
到
路径不是
路径。
4.对于iOS,Linux和Mac,看起来您不必为他们下载任何其他内容或执行此步骤。 它们通常内置了本机预编译的Sqlite库。
在Build中包含Database文件:
1.在
文件夹中创建一个文件夹,并将其命名为StreamingAssets 。 拼写很重要,而且区分大小写。
2.在此StreamingAssets文件夹中输入数据库文件( TBLDatabase.db
)。
在构建项目后访问数据库文件
Sqlite无法处理构建中StreamingAssets文件夹中的文件,因为这是一个只读路径。 此外,Android要求您使用WWW
API而不是标准System.IO
API从StreamingAssets文件夹中读取。 您必须将Application.streamingAssetsPath/filename.db
文件从Application.streamingAssetsPath/filename.db
复制到Application.persistentDataPath/filename.db
。
在某些平台上,您需要在Application.persistentDataPath
创建一个文件夹,并将数据保存到该文件夹。 总是这样做。 下面示例代码中的文件夹是“data”,因此将成为Application.persistentDataPath/data/filename.db
。
3 .。由于上述语句,请检查Application.persistentDataPath/data/filename.db
是否存在数据库文件。 如果是,请使用Application.persistentDataPath/data/filename.db
作为数据库操作的路径。 如果没有,继续#4。
4.将数据库文件从StreamingAssets文件夹中读取并复制到Application.persistentDataPath
在某些平台上,您需要在Application.persistentDataPath
创建一个文件夹,并将数据保存到该文件夹。 总是这样做。 以下示例中的文件夹是“data”。
检测这是否是Android并使用WWW
从Application.streamingAssetsPath/filename.db
读取该文件。 使用File.ReadAllBytes
在除Android之外的任何其他内容上读取它。 在您的示例中,您使用了Application.platform
。 在我的示例中,我将简单地检查路径是否包含"://"
或:///
来执行此操作。
5.一旦读取文件,使用File.WriteAllBytes
将刚刚读取的数据写入Application.persistentDataPath/data/filename.db
。 现在,您可以使用此路径进行数据库操作。
6.将"URI=file:"
前缀添加到Application.persistentDataPath/data/filename.db
路径,并且该路径应该在使用Sqlite API的数据库操作中使用。
理解所有这些是非常重要的,以便在发生变化时修复它,但我已经完成了下面的步骤#3到#6 。
IEnumerator RunDbCode(string fileName) { //Where to copy the db to string dbDestination = Path.Combine(Application.persistentDataPath, "data"); dbDestination = Path.Combine(dbDestination, fileName); //Check if the File do not exist then copy it if (!File.Exists(dbDestination)) { //Where the db file is at string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName); byte[] result; //Read the File from streamingAssets. Use WWW for Android if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///")) { WWW www = new WWW(dbStreamingAsset); yield return www; result = www.bytes; } else { result = File.ReadAllBytes(dbStreamingAsset); } Debug.Log("Loaded db file"); //Create Directory if it does not exist if (!Directory.Exists(Path.GetDirectoryName(dbDestination))) { Directory.CreateDirectory(Path.GetDirectoryName(dbDestination)); } //Copy the data to the persistentDataPath where the database API can freely access the file File.WriteAllBytes(dbDestination, result); Debug.Log("Copied db file"); } try { //Tell the db final location for debugging Debug.Log("DB Path: " + dbDestination.Replace("/", "\\")); //Add "URI=file:" to the front of the url beore using it with the Sqlite API dbDestination = "URI=file:" + dbDestination; //Now you can do the database operation below //open db connection var connection = new SqliteConnection(dbDestination); connection.Open(); var command = connection.CreateCommand(); Debug.Log("Success!"); } catch (Exception e) { Debug.Log("Failed: " + e.Message); } }
用法 :
string dbFileName = "TBLDatabase.db"; void Start() { StartCoroutine(RunDbCode(dbFileName)); }