Перевод кодировки не работает на некоторых ПК

Я борюсь с проблемой перевода кодировки Mazovia (старая польская кодировка) в Unicode. Я использовал реализацию класса кодирования Мазовии, найденную здесь: ссылка. Я использую этот класс для перевода значений из файлов DBF с помощью метода:

        public static string AsUnicode(string text)
        {
           string result =  System.Text.Encoding.Unicode.GetString(
                    System.Text.Encoding.Convert(new Mazovia(),
                                                 System.Text.Encoding.Unicode,
                                                 System.Text.Encoding.GetEncoding(852).GetBytes(text)));



           return result;
        }

До того, как я использовал, но почему-то он перестал работать через несколько недель. открытая статическая строка AsLatin2(текст строки) {

           string result =  System.Text.Encoding.GetEncoding(1250).GetString(
                    System.Text.Encoding.Convert(new Mazovia(),
                                                 System.Text.Encoding.GetEncoding(1250),
                                                 new Mazovia().GetBytes(text)));

           return result;
        }

Новое решение отлично работало на моем компьютере и на нескольких других, на которых я его тестировал, однако оно работает не на всех устройствах. На некоторых это все еще читает знаки как "?" вместо "Ł".

Engoding работает как на польском, так и на английском Windows 7/8, но только на некоторых кодировках не работает, и я понятия не имею, что может быть проблемой. У кого-нибудь была похожая проблема с классами кодирования - разное поведение в разных экземплярах ОС Windows?

Это вся реализация Encodinf для Мазовии, которую я использую:

общедоступный закрытый класс MazoviaEncoder: Encoder {частный словарь-переводчик = новый словарь ();

    internal MazoviaEncoder()
    {
        for (byte i = 0x00; i < 0x80; i++)
        {
            char c = (char)i;
            Translator.Add(c, i); // znaki poniżej 128 to standardowe kody ASCII
        }
        for (byte i = 0x00; i < 0x80; i++)
        {
            char c = (char)MazoviaAsUnicode.Content[i];
            Translator.Add(c, (byte)(i + 0x80)); // znaki powyżej 127 to kody zgodne z Mazovią - trzeba użyć słownika translacji
        }
    }

    public override int GetByteCount(char[] chars, int index, int count, bool flush)
    {
        // Mazovia jest jednobajtową stroną kodową, więc ilość bajtów dla podanej długości tekstu "count",
        // jest równa tej długości (jeden unikodowy, dwubajtowy znak równa się jednemu bajtowi Mazovii)
        return count;
    }

    public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex, bool flush)
    {
        byte b;
        for (int i = 0; i < charCount; i++)
        {
            if (!Translator.TryGetValue(chars[charIndex + i], out b))
                b = 0x3F;
            bytes[byteIndex + i] = b;
        }
        return charCount;
    }

}

internal static class MazoviaAsUnicode
{
    public static readonly short[] Content = {
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x0105, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0107, 0x00C4, 0x0104,
0x0118, 0x0119, 0x0142, 0x00F4, 0x00F6, 0x0106, 0x00FB, 0x00F9,
0x015A, 0x00D6, 0x00DC, 0x00A2, 0x0141, 0x00A5, 0x015B, 0x0192,
0x0179, 0x017B, 0x00F3, 0x00D3, 0x0144, 0x0143, 0x017A, 0x017C,
0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0};
}

public sealed class MazoviaDecoder : Decoder
{
    private char[] Translator = new char[256];

    internal MazoviaDecoder()
    {
        for (byte i = 0x00; i < 0x80; i++)
        {
            char c = (char)i;
            Translator[i] = c; // znaki poniżej 128 to standardowe kody ASCII
        }
        for (byte i = 0x00; i < 0x80; i++)
        {
            char c = (char)MazoviaAsUnicode.Content[i];
            Translator[i + 0x80] = c; // znaki powyżej 127 to kody zgodne z Mazovią - trzeba użyć słownika translacji
        }
    }

    public override int GetCharCount(byte[] bytes, int index, int count)
    {
        // Mazovia jest jednobajtową stroną kodową, więc ilość znaków dla podanej ilości bajtów "count",
        // jest równa tej właśnie ilości (jeden bajt Mazovii równa się dwubajtowemu znakowi)
        return count;
    }

    public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
    {
        for (int i = 0; i < byteCount; i++)
            chars[charIndex + i] = Translator[bytes[byteIndex + i]];
        return byteCount;
    }

}

public class Mazovia : System.Text.Encoding
{
    public static MazoviaEncoder GetMazoviaEncoder()
    {
        return new MazoviaEncoder();
    }

    public static MazoviaDecoder GetMazoviaDecoder()
    {
        return new MazoviaDecoder();
    }

    public override int GetByteCount(char[] chars, int index, int count)
    {
        return GetMazoviaEncoder().GetByteCount(chars, index, count, false);
    }

    public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
    {
        return GetMazoviaEncoder().GetBytes(chars, charIndex, charCount, bytes, byteIndex, false);
    }

    public override int GetCharCount(byte[] bytes, int index, int count)
    {
        return GetMazoviaDecoder().GetCharCount(bytes, index, count);
    }

    public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
    {
        return GetMazoviaDecoder().GetChars(bytes, byteIndex, byteCount, chars, charIndex);
    }

    public override int GetMaxByteCount(int charCount)
    {
        return charCount;
    }

    public override int GetMaxCharCount(int byteCount)
    {
        return byteCount;
    }
}

    public class External
    {
        [Microsoft.SqlServer.Server.SqlFunction()]
        public static SqlString AsMazovia(SqlString text)
        {
            if (text.IsNull)
                return SqlString.Null;
            byte[] b = text.GetNonUnicodeBytes();
            char[] c = new char[b.Length];
            Mazovia Mazovia = new Mazovia();
            Mazovia.GetChars(b, 0, b.Length, c, 0);
            StringBuilder sb = new StringBuilder(b.Length);
            foreach (var i in c)
                sb.Append(i);
            SqlString result = new SqlString(sb.ToString());
            return result.Value;
        }
        public static string AsUnicode(string text)
        {
           string result =  System.Text.Encoding.Unicode.GetString(
                    System.Text.Encoding.Convert(new Mazovia(),
                                                 System.Text.Encoding.Unicode,
                                                 System.Text.Encoding.GetEncoding(852).GetBytes(text)));



           return result;
        }
    }

Код, который я использую для загрузки данных из файла.DBF, выглядит следующим образом:

            string strAccessConn = @"Provider=vfpoledb;uid=admin;Collating Sequence=machine;Data                                                                           Source=...\latin2;CodePage=852";
            string strAccessSelect = "SELECT NAME FROM TABLE";

            DataSet myDataSet = new DataSet();
            OleDbConnection myAccessConn = null;
                myAccessConn = new OleDbConnection(strAccessConn);
                OleDbCommand myAccessCommand = new OleDbCommand(strAccessSelect, myAccessConn);
                OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(myAccessCommand);

                myAccessConn.Open();
                myDataAdapter.Fill(myDataSet, "TABLE");
                return null;
                myAccessConn.Close();

            DataTableCollection dta = myDataSet.Tables;
            foreach (DataTable dt in dta)
            {
...
}

Это один из многих провайдеров, которые используют bith odbc и oleDB.

1 ответ

Решение

Как читать файлы DBF, закодированные в кодировке Mazovia с использованием C#, независимо от версии ОС Windows?

Я не уверен, что именно происходит в твоем случае.

Хотя в некоторых статьях говорится, что его можно прочитать с помощью поставщика Microsoft OLE DB для Visual FoxPro (например, переполнение стека: как прочитать файл dbase и применить другое декодирование?), К счастью, формат файла DBF задокументирован (например, стек Переполнение: код или инструменты для экспорта FoxPro в dBase), и его можно читать без каких-либо сложных в настройке сторонних инструментов.

Одна надежная исполняемая спецификация формата файла в Delphi язык доступен в оставленном сейчас компоненте tDBF хранилища для Delphi и BCB - Browse /TDbf Win32_Linux на SourceForge.net.

Еще одна заброшенная исполняемая спецификация формата файла в C# язык (с неизвестной надежностью) доступен по адресу https://github.com/ekonbenefits/dotnetdbf.

В частности, https://github.com/ekonbenefits/dotnetdbf/blob/master/DotNetDBF/DBFReader.cs#L258 - это место, где ваш пользовательский декодер может быть подключен или вы можете подключить свой Mazovia Класс в https://github.com/ekonbenefits/dotnetdbf/blob/master/DotNetDBF/DBFBase.cs#L27

Использование вашего специального C# reader под вашим полным контролем должно дать вам независимость и надежность версии ОС, кроме того, ваши пользователи не будут вынуждены вводить некоторые версии драйверов /32-бит /64-битный ад.

Другие вопросы по тегам