開發Windows Mobile簡單dict字典-以SQLite為例 (1)

開發Windows Mobile簡單dict字典-以SQLite為例

根據<<拆解 DICT dictionary>>這一篇分享自己拆解*.dict檔的內容並另存成文字檔的方式,這一次是使用把拆解出來的內容,

儲存於SQLite小型database之中。這篇的內容,不會提太多相關於SQLite的原理,我打算分享如何在Windows Mobile上開發

使用SQLite的使用方式,另外提供自己能夠拿來用的於自己手機上的小型字典。

要透過C#開始支援SQLite的程式,可以透過System.Data.SQLite所提供的Librar來開發程式。目前的版本支援到 1.0.65.0

該社群的人所撰寫的Library,還提供完整的說明文件:SQLite.NET.chm,所以大家如果這篇看了還不是很清楚的話,可以下載

System.Data.SQLite的binaries版本下來仔細閱讀。以下將說明開發此次範例的程式說明:

1. 建立字典資料庫

    可參考<<拆解 DICT dictionary>>所提供的拆解方式,將原本文章針對寫到文字檔的對象改為寫入SQLite資料庫之中,因此,下方

    只提供C#如何建立與連線SQLite資料庫的簡單程式片段。另外,建立的拆解C#應用程式專案,記得將System.Data.SQLite所提供

    的二個重要DLL(System.Data.SQLite.DLLSystem.Data.SQLite.Linq.dll),加入該專案的參考之中。(建議把該檔案放入至開發

    專案的\bin\Debug目錄下)如下圖:

    image 000 

    1-1. 程式片段:建立一個資料庫,新增一個Vocabulary資料表(具有v_id, word, meaning三個欄位)、並建立該Vocabulary資料表的index。

   1: string filePath="dictionary.db";
   2: SQLiteConnection.CreateFile(filePath);
   3: using (SQLiteConnection sqliteCon = new SQLiteConnection("Data Source=" + filePath))
   4: {
   5:   sqliteCon.Open();
   6:   string sql = "CREATE TABLE Vocabulary ('v_id' INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL , 'word' VARCHAR, 'meaning' TEXT); " +
   7:                "CREATE INDEX 'word_idx' ON 'Vocabulary' ('word' ASC); ";
   8:   SQLiteCommand sqliteCmd = new SQLiteCommand(sql, sqliteCon);
   9:   int isSus = sqliteCmd.ExecuteNonQuery();
  10:   if (isSus == -1) {
  11:      MessageBox.Show("Error");
  12:   }
  13:   else {
  14:      MessageBox.Show("Create DataBase File Successful!");
  15:   }
  16:   sqliteCmd.Dispose();
  17:   sqliteCon.Clone();
  18: }

    1-2. 將拆解好的資料,填寫回資料庫之中。

   1: using (SQLiteConnection sqliteCon = new SQLiteConnection("Data Source=" + filePath))
   2: {
   3:   sqliteCon.Open();
   4:   SQLiteCommand sqliteCmd = new SQLiteCommand();
   5:   sqliteCmd.Connection = sqliteCon;
   6:   sqliteCmd.CommandText = "INSERT INTO Vocabulary (word, meaning) Values(@word, @meaning); ";
   7:   sqliteCmd.Parameters.Add("@word", DbType.String);
   8:   sqliteCmd.Parameters.Add("@meaning", DbType.String);
   9:   for (i = 0; i < count; i++)
  10:   {                            
  11:     sqliteCmd.Parameters["@word"].Value = wordList[i].word_str;
  12:     sqliteCmd.Parameters["@meaning"].Value = System.Text.Encoding.UTF8.GetString(baBuffer, 0, wordList[i].data_size).Replace("\n", "\r\n");
  13:     result=sqliteCmd.ExecuteNonQuery();
  14:   }
  15:   sqliteCmd.Dispose();
  16:   sqliteCon.Close();
  17: }

2. 建立一行動裝置程式

    建立智慧型行動裝置程式時,一樣要加入支援CompactFramework資料夾中的System.Data.SQLite.DLLSQLite.Interop.065.DLL

    你會發現透過VS2008加入SQLite.Interop.065.DLL時會出現錯誤沒有辦法讓你加入或者是透過Windows Mobile模擬器執行程式時會發

    現出現錯誤訊息,可以按照下方所提供的解決方法來解決這個問題。(另外,拆解好的資料庫也是透過下方的方式加入到模擬器中測試)。

   【注意

    如果你在編譯程式的過程中,進行Debug模式下,遇到「Can't find PInvoke DLL 'SQLite.Interop.060.DLL」這段文字時,主要是因為,

    我們都知道要引用別人的DLL檔到程式開發時,會先透過Visual Sutdio中的「加入參考」去選擇所要參考的Library,不過,你會發現在

    加入SQLite.Interop.060.DLL會失敗,加不進去參考,那該怎辦呢?常見的作法,會直接甘脆把該SQLite.Interop.060.DLL直接Copy到

    專案編輯目錄中的 \bin 底下,讓程式在執行時,直接Copy到編譯的目錄下,但Visual Studio並不會幫你把該DLL自動Copy到WM Emulator

    因此,你需要自行透過手動的方式,把SQLite.Interop.060.DLL複製你程式執行的目錄下(也就是跟.exe相同的目錄),即可解決該問題。

    作法步驟說明如下:

    1. 透過Visual Studio 2008所提供的 Remote File Viewer 工具來連線WM Emulator

        該工具位在:「開始\Visual Studio 2008\CE Remote Tools\」之中,或是「C:\Program Files\CE Remote Tools\5.01\bin\ccfilevw.exe"」。

        image

    2. 開啟 Remote File Viewer 工具後,選擇目前正在使用的 WM Emulator。

    3. 將SQLite.Interop.060.DLL透過Export File的功能,輸入至程式執行的目錄。(假設專案目錄為dictApp,則將檔案放置該目錄下)

        image

  2-1. 程式片段:當按照上面步驟加入SQLite.Interop.060.DLL與字典資料庫之中,接下來的程式撰寫就跟我們在寫一般Win Form操作

         SQLite一般。如下範例:

   1: using (SQLiteConnection sqliteCon = new SQLiteConnection("Data Source=" + filePath))
   2: {
   3:   sqliteCon.Open();
   4:   SQLiteCommand sqliteCmd = new SQLiteCommand();
   5:   sqliteCmd.Connection = sqliteCon;
   6:   sqliteCmd.CommandText = "SELECT word, meaning FROM vocabulary WHERE word =@word"; 
   7:   sqliteCmd.Parameters.Add("@word", DbType.String);
   8:   sqliteCmd.Parameters["@word"].Value = txtWord.Text;
   9:   SQLiteDataReader sqliteDR = sqliteCmd.ExecuteReader();
  10:   if (sqliteDR.Read()) {
  11:     result = sqliteDR["meaning"].ToString();
  12:   }
  13:   else {
  14:     result = "未找到相關[" + _word + "]的字義!";
  15:      }
  16:      sqliteDR.Close();
  17:      sqliteDR.Dispose();
  18: }

【開發後記】

當初在不使用SQLite做為字典存儲資料之前,我原本是預設使用DICT的檔案格式(*.idx與*.dict),透過二個原始的檔案,在程式執行時再

進行讀取字典索引檔(idx)到記憶體中,方便查詢,但測試出來的結果,發現這樣的做法,對於一些手機他記憶體比較小或是開啟多個程式

時,要讀取與剖析這份idx會花上大量的時間,因此取消透過實體DICT檔案格式,改由將DICT檔格拆解並儲存於SQLite之中,透過原有SQLite

本身對於資料搜尋與最佳化的方式,讓效能有所改善。 另外,我針對此資料庫新增了該單字資料表的索引,並且透過SQLite的Compact技術

將資料庫進行壓縮,讓檔案大小變的更適合於行動裝置上使用,下一篇將會更詳細說明開發的成果與設計方式。 

References:

http://sqlite.phxsoftware.com/forums/p/1569/6785.aspx#6785

http://circlep.pixnet.net/blog/post/25380869