Russian Qt Forum
Ноябрь 24, 2024, 14:56 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Класс-интерфейс для работы с DBF  (Прочитано 14882 раз)
Astrologer
Гость
« : Октябрь 12, 2010, 18:58 »

Всем привет. Нет ли у кого нить интерфейса для DBF - чтобы записывать параметры файла (количество полей, тип полей и данные)?
Записан
Zmeishe
Гость
« Ответ #1 : Октябрь 12, 2010, 19:24 »

Куда записывать? И какого dbf?
Есть описание формата файла dbf(простой таблицы dbf без индексов и MEMO полей). Есть алгоритм чтения/записи простого dbf.
Этого мало или достаточно?
Записан
Astrologer
Гость
« Ответ #2 : Октябрь 12, 2010, 19:32 »

Вообще нужно сделать запись таблицы QSqlModel или QTableView в DBF файл. Видимо придется все самому писать. Обычный DBF,без memo и всяких прибамбасов.
Записан
Zmeishe
Гость
« Ответ #3 : Октябрь 12, 2010, 19:39 »

Утром скину.
Если не втерпёж - в Инете полно описаний структуры dbf.
Записан
Astrologer
Гость
« Ответ #4 : Октябрь 12, 2010, 19:43 »

Да, спасибо. Мне не к спеху. Описания видел. Если что то не получится, буду сам писать.
Записан
Zmeishe
Гость
« Ответ #5 : Октябрь 13, 2010, 08:05 »

Эти структуры взяты мной из Инета. Я даже не стал менять комментарии на кириллицу.
Код:
typedef struct
{
 unsigned char id;
 unsigned char YY;
 unsigned char MM;
 unsigned char DD;
 unsigned long recordCount;
 unsigned short headerSize;
 unsigned short recordSize;
 unsigned char reserved1[17];
 unsigned char codePage;
 unsigned char reserved2[2];
} QDBFHeader;

typedef struct
{
  unsigned char fieldName[11]; //nazwa rekordu
  unsigned char fieldType;     /* typ pola : C(har) 43h   | D(ata) 44h /
    L(ogical) 4ch | M(emo) 4dh /
    N(umeric) 4eh |       */
  unsigned char reserved[4];   //zarezerwowane
  unsigned char fieldLen[2];   /* dla numerycznych 1 bajt = dlugosc pola
  2 bajt = ilosc miejsc po przecinku
dla innych typow 1 bajt = dlugosc pola
  2 bajt = nieuzywany   */
  unsigned char notused[14];   // nieuzywane
} QDBFField;

Эту функцию привожу свою - без переделок.
Класс QSocketModel наследник от QAbstractTableModel : public QAbstractItemModel.
Поэтому есть мои функции, которые тебе надо будет выкинуть.
Например, isActive().

В общем, разбирайся и спрашивай если что.
Код:
void QSocketModel::saveToDBF(const QString & fileName, QTextCodec *codec)
{
 unsigned int recordCountDbfPortion = 100;
 unsigned int i, j, dbfFieldCount;
 unsigned short k;
 char *buf, *b, term;
 QString str;
 QDBFHeader *hdr;
 QDBFField *fld, *p_fld;
 QFile file(fileName);
 QFileInfo fileInfo(file);
 QDataStream fileStream(&file);

 if(!isActive()) return;

 hdr = NULL; fld = NULL; buf = NULL;

    if (file.exists())
     if(!file.remove()){
      throw QDBError(trUtf8("Невозможно удалить файл."));
     }
   
    if(!file.open(QIODevice::ReadWrite))                                 
      throw QDBError(trUtf8("Невозможно создать файл."));

 try{
    blockSignals( true );
    dbfFieldCount = Fields->count();
    hdr = (QDBFHeader*) malloc(sizeof(QDBFHeader));
    fld = (QDBFField*) malloc(dbfFieldCount * sizeof(QDBFField));
    memset(hdr, 0x00, sizeof(QDBFHeader));
    memset(fld, 0x00, dbfFieldCount * sizeof(QDBFField));

    hdr->id = 0x03;

    // Convert 2006 to 06
    hdr->YY = QString::number( QDate::currentDate().year() ).remove(0, 2).toUShort();
    hdr->MM = QDate::currentDate().month();
    hdr->DD = QDate::currentDate().day();
    hdr->recordCount = recordCount();
    hdr->headerSize = sizeof(QDBFHeader) + dbfFieldCount * sizeof(QDBFField) + 1;

    if(codec == QTextCodec::codecForName("CP1251")) hdr->codePage = (unsigned char) 0x57;
    else if(codec == QTextCodec::codecForName("CP866")) hdr->codePage = (unsigned char) 0x26;
   
    for(i = 0, p_fld = fld, hdr->recordSize = 1; i < dbfFieldCount; ++i, ++p_fld)
    {
        str = Fields->Fields[i]->fieldName().left(10);
        memcpy(p_fld->fieldName, str.toLatin1().data(), str.length());
       switch(Fields->Fields[i]->dataType())
        {
         case QField::ftBCD:
           p_fld->fieldType = 'N';
           p_fld->fieldLen[0] = Fields->Fields[i]->sqlPrecision();
           p_fld->fieldLen[1] = 0 - Fields->Fields[i]->sqlScale();
         break;
         case QField::ftDouble:
           p_fld->fieldType = 'N';
           p_fld->fieldLen[0] = 20;
           p_fld->fieldLen[1] = 10;
         break;
         case QField::ftDate:
         case QField::ftDateTime:
           p_fld->fieldType = 'D';
           p_fld->fieldLen[0] = 8;
         break;
         case QField::ftInteger:
           p_fld->fieldType = 'N';
           p_fld->fieldLen[0] = 10;
         break;
         case QField::ftSmallint:
          p_fld->fieldType = 'N';
          p_fld->fieldLen[0] = 5;
         break;
         case QField::ftLargeint:
          p_fld->fieldType = 'N';
          p_fld->fieldLen[0] = 20;
         break;
         case QField::ftString:
          p_fld->fieldType = 'C';
          p_fld->fieldLen[0] = Fields->Fields[i]->sqlSize();
         break;
         case QField::ftBoolean:
          p_fld->fieldType = 'L';
          p_fld->fieldLen[0] = Fields->Fields[i]->sqlSize();
         break;
         default:
          throw QDBError(trUtf8("В этой версии QSocketModel "
                                "тип поля '") + Fields->Fields[i]->fieldName() +
                                  trUtf8("' не может быть сохранён в Dbf файле."));
         
        }
     
      hdr->recordSize += (unsigned short) p_fld->fieldLen[0];
   }
   
    fileStream.writeRawData((char*)hdr, sizeof(QDBFHeader));
    fileStream.writeRawData((char*)fld, dbfFieldCount * sizeof(QDBFField));

    term = 0x0D; // Завершающий символ конца заголовка
    fileStream.writeRawData(&term, sizeof(unsigned char));

    i = 0;
    buf = (char*) malloc(recordCountDbfPortion * hdr->recordSize);
    b = buf;
    first();
    while( !isEof() ){
    // Метка - удалена запись или нет
    if(codec) *b = codec->fromUnicode( QString::fromUtf8(" ") ).at(0);
    else *b = QString::fromUtf8(" ").at(0).toLatin1();

    b++;

    for(j = 0, p_fld = fld; j < dbfFieldCount; ++j, ++p_fld)
    {     
       k = (unsigned short) p_fld->fieldLen[0];

       if(Fields->Fields[j]->isNull()) str = QString(k, QString::fromUtf8(" ").at(0));
       else
       switch(p_fld->fieldType)
        {
         case 'D':
          str = Fields->Fields[j]->toDate().toString("yyyyMMdd");
         break;
         case 'N':
          str = QString::number(Fields->Fields[j]->toDouble(), 'f', 0 - Fields->Fields[j]->sqlScale());
          if(str.length() > k) str.resize( k );
          else str = QString(k - str.length(), QString::fromUtf8(" ").at(0)) + str;
         break;
         case 'C':
         case 'L':
          str = Fields->Fields[j]->toString();
          if(str.length() > k) str.resize( k );
          else str += QString(k - str.length(), QString::fromUtf8(" ").at(0));
         break;
        }

       if(codec) str = codec->fromUnicode( str );

       memcpy(b, str.toLatin1().data(), k);

       b += k;
    }

   ++i;
   
    if(i == recordCountDbfPortion)
    {
     fileStream.writeRawData(buf, i * hdr->recordSize);
     i = 0;
     b = buf;
    }

     next();

    } // while

    if(i > 0){
     fileStream.writeRawData(buf, i * hdr->recordSize);
    }


    term = 0x1A; // Завершающий символ конца файла
    fileStream.writeRawData(&term, sizeof(char));
  }
  catch(QDBError & e)
  {     
      blockSignals( false );
      if(hdr != NULL) free(hdr);
      if(fld != NULL) free(fld);
      if(buf != NULL) free(buf);
      file.close();
      file.setPermissions(QFile::ReadOwner | QFile::WriteOwner |
                          QFile::ReadGroup | QFile::WriteGroup |
                          QFile::ReadOther | QFile::WriteOther);
     
   throw e;
  }

      blockSignals( false );
      if(hdr != NULL) free(hdr);
      if(fld != NULL) free(fld);
      if(buf != NULL) free(buf);
      file.close();
      file.setPermissions(QFile::ReadOwner | QFile::WriteOwner |
                          QFile::ReadGroup | QFile::WriteGroup |
                          QFile::ReadOther | QFile::WriteOther);
}
Записан
Astrologer
Гость
« Ответ #6 : Октябрь 13, 2010, 11:17 »

Спасибо большое, разбираюсь.
Код:
p_fld->fieldLen[0] = Fields->Fields[i]->sqlSize();
Код:
unsigned int recordCountDbfPortion = 100;
Это что у вас?


« Последнее редактирование: Октябрь 13, 2010, 11:20 от Astrologer » Записан
Zmeishe
Гость
« Ответ #7 : Октябрь 13, 2010, 11:36 »

Код:
p_fld->fieldLen[0] = Fields->Fields[i]->sqlSize();
Fields - указатель на класс полей(столбцов) в модели.
Fields[ i ] - список QList столбцов в модели.
sqlSize() - длина поля. у меня эта модель заточена под InterBase/FireBird.
Для строковых полей это максимальная длина. VARCHAR(10), т.е. sqlSize = 10

Код:
unsigned int recordCountDbfPortion = 100;
В dbf файл строки из модели записываю порциями. Это размер порции в строках.
Для экономии памяти. Хотя в век дешёвых гигабайтов... Смеющийся
Записан
Astrologer
Гость
« Ответ #8 : Октябрь 13, 2010, 11:53 »

Код:
for(i = 0, p_fld = fld, hdr->recordSize = 1; i < dbfFieldCount; ++i, ++p_fld)
        {
            str = headerItems.at(i).left(10);//header List
            memcpy(p_fld->fieldName, str.toLatin1().data(), str.length());
            //just "C" fields for now
            p_fld->fieldType = 'C';
            p_fld->fieldLen[0] = str.length();//which is 10
            hdr->recordSize += (unsigned short) p_fld->fieldLen[0];
        }

То есть как то так? То есть можно не сокращать для 10 символов?

Что такое next(), first(),  while( !isEof() ) ?
« Последнее редактирование: Октябрь 13, 2010, 12:05 от Astrologer » Записан
Zmeishe
Гость
« Ответ #9 : Октябрь 13, 2010, 12:05 »

Ну, ты, блин даёшь.

Круто вырезал кусок кода.
У меня было
Код:
str = Fields->Fields[i]->fieldName().left(10);
Т.е. названия полей в dbf не могут превышать 10 символов.
В InterBase могут быть 67, в FireBird 31(32)
Поэтому для dbf делаем обрезание до 10.

Код:
p_fld->fieldLen[0]
Здесь указывается длина поля. Длина содержимого поля, а не имени поля.
Т.е.
p_fld->fieldName - не больше десяти
p_fld->fieldLen[0] - для строковых полей столько, сколько надо (как в БД объявлено так и ставь)
Записан
Zmeishe
Гость
« Ответ #10 : Октябрь 13, 2010, 12:11 »

Цитата: Astrologer
Что такое next(), first(),  while( !isEof() ) ?
Функции моей модели
first() - делает первую строку текущей
next() - делает следующую строку текущей
isEof() - сигналит достигнута последняя строка или ещё нет.
Код:
first(); // Встаём на начало
while( !isEof() ) // погнали по всем строкам от первой и до конца.
{
...
 next();
}
Записан
Astrologer
Гость
« Ответ #11 : Октябрь 13, 2010, 12:11 »

У меня объявлено "text" (база Sqlite).  Непонимающий
Записан
Zmeishe
Гость
« Ответ #12 : Октябрь 13, 2010, 12:18 »

Я не знаю sqllite.
Если text для sqllite  - это MEMO для DBF, замени text на строку.

Во втором посте ты написал.
Цитата: Astrologer
Обычный DBF,без memo и всяких прибамбасов.
« Последнее редактирование: Октябрь 13, 2010, 13:06 от Zmeishe » Записан
Astrologer
Гость
« Ответ #13 : Октябрь 13, 2010, 12:55 »

А все, вроде понял. Извиняюсь. Просто сначала я считываю dbfы в базу, потом добавляю к ним еще поля и теперь мне таблицу нужно снова засунуть в dbf.
Записан
mkv
Гость
« Ответ #14 : Октябрь 13, 2010, 13:39 »

я вот тоже свою реализацию писал... а потом увидел https://code.google.com/p/qdbf/
и там, как и у меня, есть реализация модели для dbf (QAbstractTableModel)
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.047 секунд. Запросов: 21.