Услуги Сертификаты Новости Статьи База знаний Алгоритмы Портфолио Скачать Ссылки Поиск
Услуги arrow Новости arrow Работа с DBF из C#
Работа с DBF из C# Версия для печати Отправить на e-mail
31.08.2010

Всем привет!
У меня на днях возникла необходимость подключить к проекту на C# КЛАДР (Классификатор адресов России) взятый из 1С, как вспомогательный справочник. Если кто не помнит, это несколько таблиц в формате DBF с кодировкой 866 внутри.

В итоге, хочу поделиться тем, что получилось.
Итак: чтобы подключиться к таблице можно использовать несколько способов.
1. Использовать Visual FoxPro OLE DB Provider (VfpOleDB.dll);
2. Использовать драйвер VFPODBC.DLL.

Драйвер VFPODBC.DLL замечательно работает, но есть один недостаток: он не поддерживается компанией Microsoft со времен Windows 2000, о чем и написано на странице загрузки данного драйвера. Там же рекомендуется использовать для работы с DBF драйвер VFPOLEDB.DLL, который поддерживается до сих пор. Немаловажным преимуществом этого драйвера является корректная работа с фалами индексов.

В среде х64 этот драйвер как оказалось cтавится, но в списке драйверов не появляется (что и понятно, он x32). Однако, я нашел интересное упоминание о программе, входящей в комплект Windows x64: %systemdrive%\Windows\SysWoW64\odbcad32.exe (обчно C:\WINDOWS\SysWOW64\odbcad32.exe). Однако, и эта утилита позволяет лишь создать ODBC алиас для подключения к таблице базы данных. Это хоть и некрасивый, но вариант для x64 - операционных систем.

Чтобы прочитать DBF в кодировке отличной от 1251 даже с помощью драйвера приходится его сначала немного подготовить. А именно - в файле по умолчанию может быть не установлен байт, отвечающий за кодовую страницу. Это приведет к тому, что отображение содержимого таблицы в Вашем проекте примет не читаемый вид (иными словами, Вы увидите абракадабру).

Дальше - дело техники. Открываем таблицу, если нужно, выставляем кодовую страницу, сохраняем, после используем по своему усмотрению.

Так как речь идет о работе с КЛАДР, ниже будет приведен пример для работы с таблицей краев и областей (в упрощенной форме, чтобы продемонстрировать подключение к DBF-файлу).

Ниже код модуля, который, также, можно загрузить.

Заранее извиняюсь за проблемы с расцветкой синтаксиса - хайлайтер не пержил некоторые символы в коде :)

using System;
using System.Data;
using System.IO;
using System.Data.OleDb;

namespace DataControl.KLADR
{
    /// <summary>
    /// Класс работы с таблицами КЛАДР
    /// </summary>
    public class opKLADR
    {
        string tkladr = @"KLADR";
        string tsocrbase = @"SOCRBASE";

        /// <summary>
        /// Сообщение об ошибке
        /// </summary>
        public string ErrorMessage { get; set; }

        /// <summary>
        /// Возвращает байт кодовой страницы по номеру кодовой страницы
        /// </summary>
        /// <param name="CodePage">Кодовая страница</param>
        /// <returns></returns>
        private byte GetByteCodePage(int CodePage)
        {
            byte cp = 0;
            switch (CodePage)
            {
                case 437: return 0x01; //DOS USA code page 437
                case 850: cp = 0x02; break// DOS Multilingual code page 850
                case 1252: cp = 0x03; break; // Windows ANSI code page 1252
                case 10000: cp = 0x04; break// Standard Macintosh
                case 865: cp = 0x08; break// Danish OEM
                case 932: cp = 0x13; break; // Japanese Shift-JIS
                case 863: cp = 0x1C; break; // French OEM (Canada)
                case 852: cp = 0x1F; break; // Czech OEM
                case 860: cp = 0x24; break; // Portuguese OEM
                case 936: cp = 0x4D; break; // Chinese GBK (PRC)
                case 949: cp = 0x4E; break; // Korean (ANSI/OEM)
                case 950: cp = 0x4F; break; // Chinese Big5 (Taiwan)
                case 874: cp = 0x50; break; // Thai (ANSI/OEM)
                case 861: cp = 0x67; break; // Icelandic MS–DOS
                case 895: cp = 0x68; break; // Kamenicky (Czech) MS-DOS
                case 620: cp = 0x69; break; // Mazovia (Polish) MS-DOS
                case 737: cp = 0x6A; break; // Greek MS–DOS (437G)
                case 857: cp = 0x6B; break; // Turkish MS–DOS
                case 1255: cp = 0x7D; break; // Hebrew Windows
                case 1256: cp = 0x7E; break; // Arabic Windows
                case 10007: cp = 0x96; break; // Russian Macintosh
                case 10029: cp = 0x97; break; // Eastern European Macintosh
                case 10006: cp = 0x98; break; // Greek Macintosh
                case 1250: cp = 0xC8; break; // Eastern European Windows
                case 1254: cp = 0xCA; break; // Turkish Windows
                case 1253: cp = 0xCB; break; // Greek Windows
                case 1257: cp = 0xCC; break; // Baltic Windows

                case 866: cp = 0x26; break; // Russian DOS
                case 1251: cp = 0x87; break; // Russian Windows
                default: cp = 0x26; break;
            }
            return cp;
        }

        /// <summary>
        /// Проверка байта кодовой страницы таблицы
        /// </summary>
        /// <param name="fileName">Имя файла</param>
        /// <returns>Байт-код кодовой страницы таблицы</returns>
        private byte GetDbfCodepage(string fileName)
        {
            byte cp = 0;
            using (FileStream file = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                try
                {
                    file.Seek(29, SeekOrigin.Begin); // 29 байт содержит значение кодовой страницы
                    cp = Convert.ToByte(file.ReadByte());
                }
                catch (Exception ex)
                {
                    ErrorMessage = String.Format("Ошибка изменения кодовой страницы: {0}", ex.Message);
                }
            }
            return cp;
        }

        /// <summary>
        /// Установка кодовой страницы таблицы
        /// </summary>
        /// <param name="fileName">Имя файла</param>
        /// <param name="codepage">Кодовая страница</param>
        private void SetDbfCodepage(string fileName, int codepage)
        {
            byte cp = GetByteCodePage(codepage);
            using (FileStream file = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                try
                {
                    file.Seek(29, SeekOrigin.Begin); // 29 байт содержит значение кодовой страницы
                    file.WriteByte(cp);                
                }
                catch (Exception ex)
                {
                    ErrorMessage = String.Format("Ошибка изменения кодовой страницы: {0}", ex.Message);
                }
            }
        }

        /// <summary>
        /// Создать объект подключения
        /// </summary>
        /// <param name="DataPath">Путь к папке, где расположены файлы таблиц DBF</param>
        /// <returns>Объект подключения</returns>
        public OleDbConnection OleDbConn(String DataPath)
        {
            OleDbConnectionStringBuilder bldr = new OleDbConnectionStringBuilder();
            bldr.DataSource = DataPath;
            bldr.Provider = "vfpoledb.1";                     
            return new OleDbConnection(bldr.ConnectionString);
        }

        /// <summary>
        /// Прочитать dbf-файл в DataTable
        /// </summary>
        /// <param name="OleDbConn">Объект подключения к таблице</param>
        /// <param name="SQLCommandText">Текст запроса данных</param>
        /// <returns></returns>
        public DataTable GetDataTable(OleDbConnection OleDbConn, string SQLCommandText)
        {
            // Класс команды для выполнения действий над таблицей
            OleDbCommand cmd = new OleDbCommand();
            cmd.CommandText = SQLCommandText;
            cmd.Connection = OleDbConn;

            // Адаптер данных
            OleDbDataAdapter da = new OleDbDataAdapter();
            da.SelectCommand = cmd;

            // Заполняем объект данными
            DataTable tbl = new DataTable();            
            da.Fill(tbl);
            return tbl;
        }

        /// <summary>
        /// Конструктор
        /// </summary>
        public opKLADR() { }

        /// <summary>
        /// Таблица регионов/краев/областей
        /// </summary>
        /// <returns>Таблица данных</returns>
        public DataTable GetRegionTable()
        {
            if (!GetDbfCodepage(Path.Combine(Directory.GetCurrentDirectory(), @"KLADR\" + tkladr + ".DBF")).Equals(38))
            {
                SetDbfCodepage(Path.Combine(Directory.GetCurrentDirectory(), @"
KLADR\" + tkladr + ".DBF"), 38);
            }

            if (!GetDbfCodepage(Path.Combine(Directory.GetCurrentDirectory(), @"
KLADR\" + tsocrbase + ".DBF")).Equals(38))
            {
                SetDbfCodepage(Path.Combine(Directory.GetCurrentDirectory(), @"
KLADR\" + tsocrbase + ".DBF"), 38);
            }

            // Создаем соединение с базой данных
            OleDbConnection OleDbCon = OleDbConn(Path.Combine(Directory.GetCurrentDirectory(), "
KLADR"));
            // Открываем его
            OleDbCon.Open();
            DataTable dt = new DataTable();
            try
            {
                dt = GetDataTable(OleDbCon,
                    String.Format(
                    "
SELECT ALLTRIM(k.name) AS name, ALLTRIM(k.code) AS code " +
                    "
FROM {0} k, {1} sb " +
                    "
WHERE " +
                    "
k.socr = sb.scname AND (sb.`level` = '1') AND (k.code LIKE '%' + '0000000000')" +
                    "
ORDER BY k.name", tkladr, tsocrbase));
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
            }
            finally
            {
                // Закрываем соединение
                OleDbCon.Close();
            }
            return dt;
        }
    }
}

* This source code was highlighted with Source Code Highlighter.

Последнее обновление ( 06.09.2010 )