標籤:
最近一個C#小程式,希望將SQLite資料庫放在網際網路共用的位置,讓多個用戶端同時訪問。卻發現SQLite串連不上該網路位置的資料庫,而如果資料庫在本地則一切正常。
例如將SQLite資料庫 test.dat 放在共用位置:\\System\Data\test.dat,
通過SQLite建立資料庫連接,執行Open時,將拋擲異常:
SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系統找不到指定的路徑。
SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系統找不到指定的路徑。
SQLite error (14): cannot open file at line 36711 of [9491ba7d73]
“System.Data.SQLite.SQLiteException”類型的第一次機會異常在 System.Data.SQLite.dll 中發生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
在 System.Data.SQLite.SQLiteConnection.Open()
在 MyMemory.Frame.DAL.SQLiteRunner..ctor(String connectionString) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\SQLiteRunner.cs:行號 34
在 MyMemory.Frame.DAL.DatabaseServices.CreateConnection() 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行號 23
在 MyMemory.Frame.DAL.DatabaseServices.Initialize(String dataDir) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行號 54
“System.Data.SQLite.SQLiteException”類型的第一次機會異常在 MyMemory.Frame.dll 中發生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
在 System.Data.SQLite.SQLiteConnection.Open()
...
即傳入的SQLite網際網路共用路徑(以\\開頭)在SQLite內部某個環節被轉換成為了本地路徑!
問題處在SQLite提供的程式集內,那麼SQLite最新版本是否已經修複這個問題了(或是從某版故意為之,不讓訪問網際網路共用位置的檔案了呢)?
到官網http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki下載最新版本( System.Data.SQLite 1.0.94.0 (3.8.6) )替換後重試,還是出現上面的異常。
好吧,既然是開源的,那就下載原始碼,看看是什麼原因。
下載了之後,採用VS編譯,通過解決方案中內建的Test項目,可以輸入資料庫連結:
點擊Run就可以進入斷點調試了。
廢話少說,直接上結果:
Open過程問題點的方法調用過程如下
\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 2372
SortedList<string, string> opts = ParseConnectionString(
_connectionString, _parseViaFramework);
\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 1875
arParts = SQLiteConvert.NewSplit(s, ‘;‘, true, ref error);
\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConvert.cs Line 716
if ((character != EscapeChar) &&
(character != QuoteChar) &&
(character != separator))
將上面的if ( //(character != EscapeChar) && 注釋掉後半行(注意:不推薦這種注釋代碼的方法)
(character != QuoteChar) &&
(character != separator))
再編譯,重新執行Test.exe 一切OK。
至於為什麼有這個限制,原始碼中的注釋是:
// --Line 709
// HACK: Only consider the escape character to be an actual
// "escape" if it is followed by a reserved character;
// otherwise, emit the original escape character and
// the current character in an effort to help preserve
// the original string content.
// --Line 715
官方文檔說,放在網路位置共用訪問的SQLite資料庫,在某些特定情況下容易損壞。看來這個問題大神們解決不好,準備乾脆屏蔽掉這種使用方式了。
提醒一下,SQLite源碼預設用的.Net Framework 4.5,編譯時間注意切換為項目需要的.Net Framework版本。
最後提供修改後的System.Data.SQLite.dll .Net Framework 4.0版:
下載
轉載請註明出處。
(全文完)
.Net版SQLite無法訪問網路位置的資料庫檔案-winOpen,os_win.c 36702異常