Невозможно определить правильную кодировку - PullRequest
2 голосов
/ 15 февраля 2012

Мне нужно извлечь данные из некоторых старых файлов баз данных interbase, созданных с помощью InterBase 4.2.1.Я использую встроенную версию Firebird (версия 2.5.1) и .NetProvider (версия 2.7.0).Я никогда раньше не работал с interbase из firebird (но у меня есть некоторый опыт работы с SQL SERVER и SQLite), и после того, как я путешествовал по сети и экспериментировал в течение 2 дней, мне все еще не удалось найти решение.

Таблицы в базе данныхсодержат данные на английском языке, а также данные на иврите.Как бы я ни был оптимистичен, я начал с создания строки подключения с использованием UTF8:

FbConnectionStringBuilder builder = new FbConnectionStringBuilder();
builder.Database = m_DatabaseName;
builder.ServerType = FbServerType.Embedded;
builder.Charset = FbCharset.Utf8.ToString();

Но это дало мне следующее исключение:

bad parameters on attach or create database
CHARACTER SET Utf8 is not defined

Я правильно использовал fbintl.dll.(см. файлы в моем каталоге приложений и подкаталогах ниже).Я даже использовал ProcessMonitor, чтобы проверить, был ли загружен файл fbintl.dll.

fbembed.dll
firebird.log
firebird.msg
FirebirdSql.Data.FirebirdClient.dll
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
MyApplication.exe
Microsoft.VC80.CRT.manifest
msvcp80.dll
msvcr80.dll
intl\fbintl.conf
intl\fbintl.dll
udf\fbudf.dll
udf\ib_udf.dll

Поэтому я попытался перечислить FbCharset и попытаться соединиться с каждым набором символов, более половины из них выдали одно и то же исключение, икогда я связывался с другими и запрашивал одно из полей на иврите (используя IDataReader.GetString()), я всегда получал один и тот же мусор в результате.Кажется, не имеет значения, какой набор символов я указываю в строке подключения, результат всегда один и тот же, даже если я вообще не задаю какой-либо набор символов.

Далее я запросил определенные наборы символовв базе данных SELECT RDB$CHARACTER_SET_NAME FROM RDB$CHARACTER_SETS и я перечислил тех, кто пытался соединиться с каждым из них, некоторые выдавали исключение, другие давали тот же результат, что и раньше.

Я не имею ни малейшего понятия, с каким набором символов база данныхбыл создан, но я проверил наборы символов каждого поля в базе данных, и для всех текстовых полей их наборы символов установлены на «NONE».

SELECT r.RDB$RELATION_NAME, r.RDB$FIELD_NAME, f.RDB$FIELD_NAME, cset.RDB$CHARACTER_SET_NAME
FROM RDB$RELATION_FIELDS r
LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME
LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID
ORDER BY r.RDB$RELATION_NAME ASC, r.RDB$FIELD_POSITION ASC

Но я заметил, что некоторые из текстовых полей системных таблиц имеютUNICODE_FSS в качестве набора символов.Я уже пробовал этот набор символов в строке подключения, но я все еще получаю garbadge для запрошенных текстовых полей.

Моя последняя попытка состояла в том, чтобы извлечь байты (используя IDataReader.GetBytes()) и кодировать строку самостоятельно, ноэто дает мне исключение приведения (Unable to cast object of type 'System.String' to type 'System.Byte[]'.)

У кого-нибудь есть идеи о том, как читать эти данные?Мне не нужно постоянно преобразовывать базы данных, так как они больше не будут использоваться после того, как я извлеку данные.

РЕДАКТИРОВАТЬ: кстати, есть ли какие-нибудь бесплатные легковесные программы просмотра баз данных interbase / firebird, я могу 'Кажется, вы не нашли ничего хорошего (сравнимого с SQLiteSpy )?

Marc

1 Ответ

3 голосов
/ 16 февраля 2012

Я нашел решение.

Исходная база данных была написана на окнах с кодовой страницей 1255. Когда я читаю данные, теперь c # генерирует строку в кодировке Юникод, используя кодировку по умолчанию (которая не 1255).Поэтому я просто декодирую строку в байты, используя кодировку по умолчанию, а затем преобразовываю байты в строку, используя правильную кодировку.

Encoding encoding = Encoding.GetEncoding(1255);
...
if (!datareader.IsDBNull(i))
{
    string value = dataReader.GetString(i);
    if (value.Length > 0)
    {
        byte[] bytes = Encoding.Default.GetBytes(value);
        value = encoding.GetString(bytes);
    }
    // store value
 }

Это решение отлично работает для меня, но я до сих пор не понимаю, почему я могуне указать "WIN1255" в качестве charset в моей строке подключения без получения исключения bad parameters on attach or create database - CHARACTER SET WIN1255 is not defined?(Я даже попробовал кодировку "WINDOWS1255", но потом получаю исключение Invalid character set specified).

...