Поддержка длинных файловых путей Unicode с System.Data.SQLite - PullRequest
3 голосов
/ 14 января 2012

Я занимаюсь разработкой приложения, которое должно иметь возможность создавать базы данных SQLite и манипулировать ими по заданным пользователем путям. У меня проблема, которую я не понимаю. Я проверяю свои данные на некоторых действительно грубых выборочных данных с огромными громоздкими путями Юникода, для большинства из них проблем нет, но для одного есть.

Пример рабочей строки подключения:

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 хорошо играть с этими путями? Обходной путь может состоять в том, чтобы создавать и манипулировать моими базами данных во временном местоположении, а затем просто перемещать их в фактические места для хранения, поскольку в противном случае я обычно могу создавать и манипулировать файлами. Хотя это последнее средство.

Спасибо.

1 Ответ

4 голосов
/ 14 января 2012

Я предполагаю, что вы находитесь на машине с японским языком, где системная кодировка по умолчанию (кодовая страница ANSI) - cp932 Японский (≈Shift-JIS).

Второй путь содержит:

, который кодирует в последовательность байтов:

0x83 0x5C

Shift-JIS - это многобайтовая кодировка, которая имеет прискорбное свойство иногда повторно использовать единицы кода ASCII в байте следа.В этом случае он использовал байт 0x5C, который соответствует обратной косой черте \.(Хотя по историческим причинам это обычно отображается как знак иены в японских шрифтах.)

Так что, если это имя пути передается в байтовый API, оно будет закодировано в кодовой странице ANSI, и вы выиграетене может отличить обратную косую черту в качестве разделителя каталогов от побочного эффекта многобайтового кодирования.Следовательно, любой путь с одним из следующих символов не будет выполнен при доступе с помощью метода ввода-вывода на основе байтов:

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

(Также любой путь, содержащий символ Unicode, отсутствующий в cp932, естественно завершится сбоем.)

Может показаться, что за кулисами SQLite использует байтовый метод ввода-вывода, чтобы открыть заданное имя файла.Это прискорбно, но чрезвычайно распространено в кроссплатформенном коде, потому что стандартная библиотека POSIX C определена для использования байтовых имен файлов для таких операций, как file 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, поэтому вам нужна небольшая справка , чтобы вызвать его из .NET.Обратите внимание, что короткие имена файлов по-прежнему не будут работать, если они запускаются на компьютере с отключенной функцией создания коротких имен файлов;

  5. убедить SQLite добавить поддержку имен файлов Windows Unicode;

  6. убедить Microsoft решить эту проблему раз и навсегда, установив кодировку по умолчанию для байтовых интерфейсов UTF-8, как это делается во всех других современных операционных системах.

...