2012-01-13 47 views
3

我正在開發一個應用程序,需要能夠創建&在用戶定義的路徑中操作SQLite數據庫。我遇到了一個我不太瞭解的問題。我正在測試我的東西,以防一些非常笨重的樣本數據,這些樣本數據具有龐大笨重的unicode路徑,因爲他們中的大多數沒有問題,但只有一個。使用System.Data.SQLite支持長unicode文件路徑

工作連接字符串的一個例子是:

Data Source="c:\test6\意外な高価で売れるかも? 出品は手順を覚えれば後はかんたん!\11オークションストアの出品は対象外とさせていただきます。\test.db";Version=3; 

雖然一個失敗是

Data Source="c:\test6\意外な高価で売れるかも? 出品は手順を覚えれば後はかんたん!\22今やPCライフに欠かせないのがセキュリティソフト。そのため、現在何種類も発売されているが、それぞれ似\test.db";Version=3; 

我使用System.Data.SQLite v1.0.66.0由於外界原因我的控制,但我很快測試了最新的v1.0.77.0,並有同樣的問題。

當試圖新創建test.db文件,或者如果我手動將其中一個,並試圖打開,SQLiteConnection.Open拋出一個異常,只說「無法打開數據庫文件」,顯示堆棧跟蹤它實際上是拋出的System.Data.SQLite.SQLite3.Open。

有什麼辦法可以讓System.Data.SQLite與這些路徑很好地玩嗎?解決方法是在臨時位置創建和操作我的數據庫,然後將它們移動到實際存儲位置,因爲我可以正常創建和操作文件。儘管如此,這仍然是最後一招。

謝謝。

回答

4

我猜你是在一個默認系統編碼(ANSI代碼頁)是cp932日語(≈Shift-JIS)的日語區域設備上。

第二路徑包含:

其編碼的字節序列:

0x83 0x5C 

移位-JIS是具有有時不幸性的多字節編碼重新使用ASCII代碼單元在跟蹤字節中。在這種情況下,它使用了對應於反斜槓\的字節0x5C。 (儘管由於歷史原因,這通常顯示爲日文字體的日元符號。)

因此,如果將此路徑名傳遞到基於字節的API中,它將在ANSI代碼頁中進行編碼,並且您不會能夠分辨出作爲目錄分隔符的反斜線與多字節編碼的副作用之間的區別。因此用下面的字符之一當與基於字節的IO方法來訪問在將失敗的任何路徑:(同樣的任何路徑名包含Unicode字符不存在於CP932自然會失敗)

―ソЫⅨ噂浬欺圭構蠶十申曾簞貼能表暴予祿兔喀媾彌拿杤歃畚秉綵臀藹觸軆鐔饅鷭偆砡纊犾 

看來在後臺SQLite正在使用基於字節的IO方法來打開它給出的文件名。這是不幸的,但在跨平臺代碼中非常常見,因爲POSIX C標準庫被定義爲使用文件open()等操作使用基於字節的文件名。

因此,使用C stdlib函數不可能可靠地訪問非ASCII名稱的文件。這種可悲的情況繼承了使用stdlib編寫的各種跨平臺庫和語言;只有針對Win32 Unicode文件名(例如Python)編寫的工具才能可靠地訪問Windows下的所有文件。

你的選項,然後,分別是:使用

  1. 避免非ASCII字符在你的數據庫路徑名,按移動/重命名的建議;

  2. 繼續依賴系統區域設置爲日語(ANSI代碼頁= 932),只是重命名文件以避免上面列出的任何字符;

  3. 獲得有問題的文件的短文件名(8.3),並使用該文件替代真實文件名,例如c:\test6\85D0~1\22PC~1\test.db。您可以使用dir /x來查看短文件名。它們總是純粹的ASCII碼,避免了編碼問題;

  4. 添加一些代碼,使用GetShortPathName從真實文件中獲取短文件名。這是一個Win32 API,因此您需要使用一點點help來從.NET調用它。注意如果在禁用短文件名生成功能的機器上運行,短文件名仍然會失敗;

  5. 說服的SQLite以增加對Windows Unicode文件名支持;

  6. 說服微軟一勞永逸通過使默認編碼字節接口UTF-8,喜歡它是在所有其他現代操作系統解決這個問題。