Автор | Сообщение |
|
| |
Пост N: 256
Зарегистрирован: 05.10.06
|
|
Отправлено: 16.03.20 19:44. Заголовок: непосредственное изменение имени поля в заголовке dbf
Иногда требуется поменять имя поля без изменения других параметров. Если база 200-300мегов, то обновление занимает долгое время. Есть у кого нибудь опыт изменения имени непосредственно в заголовке DBF что бы не перегонять все данные ?
|
|
|
Ответов - 19
[только новые]
|
|
|
| постоянный участник
|
Пост N: 3091
Зарегистрирован: 17.02.12
|
|
Отправлено: 16.03.20 23:32. Заголовок: MIKHAIL Функции от ..
MIKHAIL Функции от Pasha к hb 2.0 Скрытый текст
#define HB_OS_WIN_USED #include "hbapi.h" #include "hbapiitm.h" #include "hbapirdd.h" #include "hbrdddbf.h" #include "hbapicdp.h" //#include "hbdate.h" #ifdef __XHARBOUR__ #define HB_SUCCESS SUCCESS #endif /* HB_FUNC( MILLIS ) { hb_retnl( hb_dateMilliSeconds() ); } */ /* HB_FUNC( DBSETCDP ) { AREAP pArea = hb_rddGetCurrentWorkAreaPointer(); if( pArea && ISCHAR(1) ) { char * pCdp = hb_parc(1); if( pCdp ) pArea->cdPage = hb_cdpFind( (char *) pCdp ); } } */ // ------------------------------- // Static func bMemoGetBlock(nPos) // Return {|| dbGetMemoBlock(nPos)} // ------------------------------- HB_FUNC( DBGETMEMOBLOCK ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); USHORT uiField = hb_parni( 1 ) - 1; #ifdef __XHARBOUR__ LPFIELD pField = pArea->lpFields + uiField; #else LPFIELD pField = pArea->area.lpFields + uiField; #endif char * ptr = ( char * ) pArea->pRecord + pArea->pFieldOffset[uiField]; ULONG ulBlock = 0; if( pField->uiLen == 4 ) ulBlock = HB_GET_LE_UINT32( ptr ); else { BYTE bByte; USHORT uiCount; for( uiCount = 0; uiCount < 10; uiCount++ ) { bByte = ptr[ uiCount ]; if( bByte >= '0' && bByte <= '9' ) ulBlock = ulBlock * 10 + ( bByte - '0' ); } } hb_retnl( ulBlock ); } // --------------------------- // Получить значение поля как строка // if FieldType(nPos) == "C"; xVal := FieldGet(nPos) // else ; xVal := dbGetValue(nPos) // endif // --------------------------- HB_FUNC( DBGETVALUE ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); USHORT uiField = hb_parni( 1 ) - 1; #ifdef __XHARBOUR__ LPFIELD pField = pArea->lpFields + uiField; #else LPFIELD pField = pArea->area.lpFields + uiField; #endif hb_retclen( ( char * ) pArea->pRecord + pArea->pFieldOffset[uiField], pField->uiLen ); } // ----------------------------- // if FieldType(nPos) == "C"; FieldPut(nPos, xVal) // else ; dbPutValue(nPos, xVal) // endif // ----------------------------- HB_FUNC( DBPUTVALUE ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); USHORT uiField = hb_parni( 1 ) - 1; #ifdef __XHARBOUR__ LPFIELD pField = pArea->lpFields + uiField; #else LPFIELD pField = pArea->area.lpFields + uiField; #endif if( ISCHAR(2) && ( hb_parclen(2) <= pField->uiLen ) ) { memcpy( ( char * ) pArea->pRecord + pArea->pFieldOffset[uiField], hb_parc(2), hb_parclen(2) ); pArea->fRecordChanged = TRUE; pArea->fDataFlush = TRUE; } hb_ret(); } // ------------------------ // Вставить запись // nKol := 1; nRec := RecNo() // dbGoto(nRec); dbInsert(nRec, nKol) // ------------------------ HB_FUNC( DBINSERT ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); BOOL bOk = TRUE; if( pArea && ! pArea->fReadonly && ! pArea->fShared ) { ULONG ulRec, ulCount = ISNUM(2) ? hb_parnl(2) : 1; #ifdef __XHARBOUR__ ULONG hFile = pArea->hDataFile; #else HB_FHANDLE hFile = hb_fileHandle( pArea->pDataFile ); #endif if( ISNUM(1) ) ulRec = hb_parnl(1); else SELF_RECNO( ( AREAP ) pArea, &ulRec ); if( ulRec == 0 || ulRec > pArea->ulRecCount ) bOk = FALSE; if( bOk && SELF_GOCOLD( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; else { ULONG ulIndex; for( ulIndex = 0; ulIndex < ulCount; ulIndex ++) SELF_APPEND( ( AREAP ) pArea, TRUE ); SELF_FLUSH( ( AREAP ) pArea ); /* pArea->fUpdateHeader = TRUE; pArea->ulRecCount += ulCount; if( SELF_WRITEDBHEADER( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; */ if( bOk ) { ULONG ulLen = (pArea->ulRecCount - ulRec) * pArea->uiRecordLen; ULONG ulLen1 = ulCount*pArea->uiRecordLen; // ULONG ulRecNo; char * pData = hb_xgrab( ulLen + 1 ); char * pZero = hb_xgrab( ulLen1 + 1 ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (ulRec - 1), FS_SET ); hb_fsReadLarge( hFile, pData, ulLen ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (pArea->ulRecCount - ulCount), FS_SET ); hb_fsReadLarge( hFile, pZero, ulLen1 ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (ulRec - 1), FS_SET ); hb_fsWriteLarge( hFile, pZero, ulLen1 ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (ulRec + ulCount - 1), FS_SET ); hb_fsWriteLarge( hFile, pData, ulLen ); hb_xfree( pData ); hb_xfree( pZero ); /* for( ulRecNo = ulRec + ulCount - 1; ulRecNo >= ulRec; ulRecNo --) { SELF_GOTO( ( AREAP ) pArea, ulRecNo ); SELF_SETBLANKRECORD( ( AREAP ) pArea, 2 ); // HB_BLANK_EOF } */ } } if( bOk && SELF_GOTO( ( AREAP ) pArea, ulRec ) != HB_SUCCESS ) bOk = FALSE; } hb_retl( bOk ); } // ---------------------------- // Физическое удаление записей // nKol := 1; nRec := RecNo() // dbGoto(nRec); dbDelRecord(nRec, nKol) // ---------------------------- HB_FUNC( DBDELRECORD ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); BOOL bOk = TRUE; if( pArea && ! pArea->fReadonly && ! pArea->fShared ) { ULONG ulRec, ulCount = ISNUM(2) ? hb_parnl(2) : 1; #ifdef __XHARBOUR__ ULONG hFile = pArea->hDataFile; #else HB_FHANDLE hFile = hb_fileHandle( pArea->pDataFile ); #endif if( ISNUM(1) ) ulRec = hb_parnl(1); else SELF_RECNO( ( AREAP ) pArea, &ulRec ); if( ulRec == 0 || (ulRec + ulCount - 1) > pArea->ulRecCount ) bOk = FALSE; if( bOk && SELF_GOCOLD( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; else { char pData; if( (ulRec + ulCount - 1) < pArea->ulRecCount ) { ULONG ulLen = (pArea->ulRecCount - (ulRec + ulCount - 1)) * pArea->uiRecordLen; char * pData = hb_xgrab( ulLen + 1 ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (ulRec + ulCount - 1), FS_SET ); hb_fsReadLarge( hFile, pData, ulLen ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) (ulRec - 1), FS_SET ); hb_fsWriteLarge( hFile, pData, ulLen ); hb_xfree( pData ); } pArea->fUpdateHeader = TRUE; pArea->ulRecCount -= ulCount; } if( bOk && SELF_WRITEDBHEADER( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; if( bOk && SELF_GOTO( ( AREAP ) pArea, ulRec ) != HB_SUCCESS ) bOk = FALSE; } hb_retl( bOk ); } // -------------------------- // Обрезать файл после записи ... // nRec := RecNo(); dbGoto(nRec) // dbTruncate(nRec) // -------------------------- HB_FUNC( DBTRUNCATE ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); BOOL bOk = TRUE; if( pArea && ! pArea->fReadonly && ! pArea->fShared ) { ULONG ulRec; if( ISNUM(1) ) ulRec = hb_parnl(1); else SELF_RECNO( ( AREAP ) pArea, &ulRec ); if( ulRec == 0 || ulRec > pArea->ulRecCount ) bOk = FALSE; if( bOk && SELF_GOCOLD( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; else { pArea->fUpdateHeader = TRUE; pArea->ulRecCount = ulRec; } if( bOk && SELF_WRITEDBHEADER( ( AREAP ) pArea ) != HB_SUCCESS ) bOk = FALSE; if( bOk && SELF_GOTO( ( AREAP ) pArea, ulRec ) != HB_SUCCESS ) bOk = FALSE; } hb_retl( bOk ); } HB_FUNC( DBRECORDGET ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); PHB_ITEM pItem = hb_itemPutNI( NULL, 0 ); BYTE *pRec; if( pArea && (SELF_INFO( (AREAP) pArea, DBI_GETRECSIZE, pItem ) == HB_SUCCESS) && ( SELF_GETREC( (AREAP) pArea, &pRec ) == HB_SUCCESS ) ) { hb_retclen( pRec, hb_itemGetNI(pItem) ); } hb_itemRelease( pItem ); } HB_FUNC( DBRECORDPUT ) { AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); PHB_ITEM pItem = hb_itemPutNI( NULL, 0 ); if( pArea && ISCHAR(1) && (SELF_INFO( (AREAP) pArea, DBI_GETRECSIZE, pItem ) == HB_SUCCESS) && hb_parclen(1) >= (ULONG) hb_itemGetNI(pItem) ) { SELF_PUTREC( pArea, hb_parc(1) ); } hb_itemRelease( pItem ); } static void SetFieldType( LPFIELD pField, char bType ) { switch( bType ) { case 'C': pField->uiType = HB_FT_STRING; break; case 'L': pField->uiType = HB_FT_LOGICAL; break; case 'D': pField->uiType = HB_FT_DATE; break; case 'I': case '2': case '4': pField->uiType = HB_FT_INTEGER; break; case 'Y': pField->uiType = HB_FT_CURRENCY; break; case 'N': pField->uiType = HB_FT_LONG; break; case 'F': pField->uiType = HB_FT_FLOAT; break; case '8': case 'B': pField->uiType = HB_FT_DOUBLE; } } // ------------------------ // Переименовать поле, поменять его тип и дробную часть // в пределах длины поля, заданную при создании dbf // FieldRename( nPos, FieldNameNew[, FieldTypeNew[, FieldDecNew]] ) // ------------------------ HB_FUNC( FIELDRENAME ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); USHORT uiField = hb_parni( 1 ); char szFieldName[12]; #ifdef __XHARBOUR__ if( uiField && uiField <= pArea->uiFieldCount && ISCHAR(2) && hb_parclen(2) <= 11 ) #else if( uiField && uiField <= pArea->area.uiFieldCount && ISCHAR(2) && hb_parclen(2) <= 11 ) #endif { char * szType = hb_parc( 3 ); #ifdef __XHARBOUR__ ULONG hFile = pArea->hDataFile; LPFIELD pField = pArea->lpFields + uiField - 1; #else HB_FHANDLE hFile = hb_fileHandle( pArea->pDataFile ); LPFIELD pField = pArea->area.lpFields + uiField - 1; #endif ULONG ulOffset = sizeof( DBFHEADER ) + (uiField-1)*sizeof( DBFFIELD ); memset(szFieldName, 0, 12); memcpy(szFieldName, hb_parc(2), hb_parclen(2) ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) ulOffset, FS_SET ); hb_fsWriteLarge( hFile, szFieldName, 11 ); pField->sym = ( void * ) hb_dynsymGetCase( szFieldName ); if( szType ) { hb_fsSeekLarge( hFile, ( HB_FOFFSET ) ( ulOffset + 11 ), FS_SET ); hb_fsWriteLarge( hFile, szType, 1 ); SetFieldType( pField, szType[0] ); } if( ISNUM( 4 ) ) { USHORT uiDec = hb_parni( 4 ); hb_fsSeekLarge( hFile, ( HB_FOFFSET ) ( ulOffset + 17 ), FS_SET ); hb_fsWriteLarge( hFile, (char *) &uiDec, 1 ); pField->uiDec = uiDec; } } } HB_FUNC( DBFRECCOUNT ) { DBFAREAP pArea = ( DBFAREAP ) hb_rddGetCurrentWorkAreaPointer(); if( pArea ) { if( ISNUM( 1 ) ) { HB_PUT_LE_UINT32( pArea->dbfHeader.ulRecCount, hb_parnl( 1 ) ); pArea->fUpdateHeader = TRUE; } hb_retnl( HB_GET_LE_UINT32( pArea->dbfHeader.ulRecCount ) ); } else hb_retnl( 0 ); } #include <windows.h> HB_FUNC( GETSYSTEMDEFAULTLANGID ) { hb_retnl( GetSystemDefaultLangID() ); }
|
|
|
|
|
| |
Пост N: 257
Зарегистрирован: 05.10.06
|
|
Отправлено: 17.03.20 07:59. Заголовок: SergKis пишет: Fiel..
SergKis пишет: цитата: | FieldRename( nPos, FieldNameNew[, FieldTypeNew[, FieldDecNew]] ) |
| А как использовать ? Я правильно понимаю, что нужно сначала открыть файл например через DBFNTX в эксклюзивном режиме (через ADS наверное работать не будет...) ?
|
|
|
|
| |
Пост N: 7175
Зарегистрирован: 17.05.05
|
|
Отправлено: 17.03.20 10:28. Заголовок: MIKHAIL пишет: (че..
MIKHAIL пишет: цитата: | (через ADS наверное работать не будет...) |
| Пробовать надо
|
|
|
|
| постоянный участник
|
Пост N: 3092
Зарегистрирован: 17.02.12
|
|
Отправлено: 17.03.20 11:10. Заголовок: MIKHAIL пишет Я прав..
MIKHAIL пишет цитата: | Я правильно понимаю, что нужно сначала открыть файл например через DBFNTX в эксклюзивном режиме |
| Именно так. Пробовал с hb 2.0 все ф-ии - работают. На 3.2 DBDELRECORD стала валить программу. В использовании остались только FIELDRENAME - для не больших файлов (определение реальной дробной части и "чужие" имена полей -> в свои) DBINSERT - для использования в файлах отчета (вставка в нужные места итоговых строк, с учетом групп, подгрупп и т.д.) С ADS не работаю.
|
|
|
|
| |
Пост N: 1527
Зарегистрирован: 20.02.11
|
|
Отправлено: 17.03.20 11:38. Заголовок: менял тупо открывая ..
менял тупо открывая файл в двоичном режиме ( Fopen() ) и записывая новое название ( и тип если требовалось ) прямо в заголовок Для dbf длинна имени поля не более 10 , заканчивается нулевым байтом. Меняется только так, мгновенно и без оглядки на размер базы В ADS может не прокатить только если используются словари - тк структура в них или база зашифрована
|
|
|
|
| |
Пост N: 258
Зарегистрирован: 05.10.06
|
|
Отправлено: 17.03.20 16:18. Заголовок: Haz пишет: Fopen() ..
Haz пишет: цитата: | Fopen() ) и записывая новое название |
| чисто теоретически понимаю что можно в бинарном режиме в заголовке вписать новое имя поля, просто на грабли наступать не хочется... Насколько помню первые 32 байта - заголовок, потом идут по 32 байта описание полей., из которых первые 10 отводятся под имя поля, куда и нужно записать коды символов имени. В бинарном режиме опыта работы мало. Какие коды писать ? нужно ли переводить в другую систему или как есть писать...?
|
|
|
|
| |
Пост N: 1528
Зарегистрирован: 20.02.11
|
|
Отправлено: 17.03.20 16:56. Заголовок: MIKHAIL пишет: Как..
MIKHAIL пишет: цитата: | Какие коды писать ? нужно ли переводить в другую систему или как есть писать...? |
| Все верно , начиная с 32 байта , каждые 32 последующие это описания полей. Описание полей заканчиваются значением 0Dh Никакая система счисление не требуется , просто пишем новое имя поля латиницей в верхнем регистре. Имя дополняем справа до длинны 10 символом chr(0) например пишем в качестве имени первого поля NEW_NAME func main() local cName := space(10) local n := FOPEN( 'demo.dbf', 2 ) // читаем имя первого поля fseek( n, 32, 0 ) fread(n, @cName, 10) ? CharRem( chr(0), cName) // пишем новое имя первому полю fseek( n, 32, 0 ) cName := PADR( "NEW_NAME" , 10, chr(0) ) fWrite( n, cName, 10 ) fClose(n) return nil
|
|
|
|
| |
Пост N: 259
Зарегистрирован: 05.10.06
|
|
Отправлено: 17.03.20 23:05. Заголовок: Haz то что надо! Не..
Haz то что надо! Не могу только разобраться с размером заголовка. По идее он прописан в 8-9 байтах я считаю: headersize=8байт+9байт*255 но не всегда выходит нужное число, проверяемое обратным методом: headersize = кол-во полей * 32 +33 что не так делаю ?
|
|
|
|
| |
Пост N: 1529
Зарегистрирован: 20.02.11
|
|
Отправлено: 17.03.20 23:14. Заголовок: MIKHAIL пишет: что ..
MIKHAIL пишет: эавтра с компа пример сброшу. С телефона неудобно
|
|
|
|
| |
Пост N: 7176
Зарегистрирован: 17.05.05
|
|
Отправлено: 18.03.20 09:55. Заголовок: может это поможет ht..
|
|
|
|
| постоянный участник
|
Пост N: 6603
Зарегистрирован: 12.09.06
|
|
Отправлено: 18.03.20 11:01. Заголовок: Всем привет ! Я не с..
Всем привет ! Я не совсем понимаю зачем нужно переименовывать поле в базе ? Просто интересно.
|
|
|
|
|
| |
Пост N: 1530
Зарегистрирован: 20.02.11
|
|
Отправлено: 18.03.20 11:05. Заголовок: MIKHAIL пишет: я сч..
MIKHAIL пишет: цитата: | я считаю: headersize=8байт+9байт*255 |
| длинна заголовка в байтах получается так ( fSeek( n, 8) cBuf := Space(2) fRead( n, @cBuf, hb_BLen(cBuf) ) ? "Header size :" , Bin2L( cBuf )
|
|
|
|
| |
Пост N: 260
Зарегистрирован: 05.10.06
|
|
Отправлено: 18.03.20 11:20. Заголовок: Dima пишет: может э..
Dima пишет: Это я знаю, тут то же самое: цитата: | Этот же размер можно извлечь из 8,9 байтов заголовка - HeaderSize |
| У меня значения байтов не сходиться почему то. Наверное не правильно вычисляю размер... Andrey пишет: цитата: | Я не совсем понимаю зачем нужно переименовывать поле в базе ? |
| Потребность возникла при обновлении больших сетевых фалов, если требуется изменить имя поля. Обычно создается новая структура и туда перегоняются данные. Это очень медленно. Если можно изменить имя поля в заголовке, без изменения структуры данных, это очень быстро. Причины для изменения могут быть у каждого свои.... Я например сделал имя которое в дальнейшем начало конфликтовать с другими подсистемами, и мне проще его поменять в заголовке чем гонять данные... Haz пишет: Попробую, спасибо.
|
|
|
|
| Администратор
|
Пост N: 3924
Зарегистрирован: 23.05.05
|
|
Отправлено: 18.03.20 20:17. Заголовок: MIKHAIL пишет: head..
MIKHAIL пишет: цитата: | headersize=8байт+9байт*255 |
| Умножать надо на 256. А лучше считать 2 байта и передать их функции Bin2I. Bin2L это для 4-х байт
|
|
|
|
| |
Пост N: 1531
Зарегистрирован: 20.02.11
|
|
Отправлено: 18.03.20 20:31. Заголовок: Pasha пишет: Bin2L ..
Pasha пишет: Да, упустил. Всё верно Bin2I
|
|
|
|
| |
Пост N: 261
Зарегистрирован: 05.10.06
|
|
Отправлено: 19.03.20 15:43. Заголовок: Haz пишет: Всё вер..
Haz пишет: Все работает, только почему то расчет кол-ва полей отличается от описанной структуры dbf кол-во полей получается по формуле (headersize-34)/32 А символ окончания заголовка - chr(13) находится по адресу headersize - 2
|
|
|
|
| |
Пост N: 1532
Зарегистрирован: 20.02.11
|
|
Отправлено: 19.03.20 16:25. Заголовок: MIKHAIL пишет: А си..
MIKHAIL пишет: цитата: | А символ окончания заголовка - chr(13) находится по адресу headersize - 2 |
| В некоторых источниках то что хранится в в 08-09 называют адресом первой записи. Может в этом дело , да и счет начинается с нулевого адреса ( а по сути он первый ) PS не проверял но вроде сходится Пусть имеем 100 полей тогда сам заголовок 32 байта + 100 дескриптор полей по 32 + терминатор = 32 + 100*32 + 1 = 3233 ( занято ) тогда в 8-9 должен быть записан адрес первой записи как 3234
|
|
|
|
| |
Пост N: 1533
Зарегистрирован: 20.02.11
|
|
Отправлено: 19.03.20 16:43. Заголовок: Haz пишет: не прове..
Haz пишет: цитата: | не проверял но вроде сходится |
| проверил по какой то dbf c двумя полями в 8-9 записано 98 считаем 32 + 2*32 + 1 = 97 значит первая запись начнется с 98
|
|
|
|
| Администратор
|
Пост N: 3925
Зарегистрирован: 23.05.05
|
|
Отправлено: 20.03.20 10:23. Заголовок: MIKHAIL пишет: Все ..
MIKHAIL пишет: цитата: | Все работает, только почему то расчет кол-ва полей отличается от описанной структуры dbf кол-во полей получается по формуле (headersize-34)/32 |
| Немного не так, формула (headersize-32)/32 Посмотрите класс для низкоуровневой работы c dbf, там разбираются разные форматы, и можно обращаться к полям по имени: oDbf:FieldName Ссылка на класс: https://cloud.mail.ru/public/458B/4hTkEJg3a PS Функцию WinToDos замените на HB_ANSITOOEM
|
|
|
|