Promotic

Struktura pliku dBase III.

Plik danych .dbf ma ściśle określoną strukturę. Składa się on z nagłówka i obszaru danych. Sam nagłówek składa się z danych globalnych opisujących plik dbf oraz listy zawierającej opisy poszczególnych elementów pliku bazy danych. Po tej liście (a więc już na końcu nagłówka) następuje obszar danych, w którym znajduje się pierwszy zapis, drugi zapis, .... do ostatniego rekordu w pliku bazy danych. Wszystkie rekordy mają tę samą długość. Strukturę przedstawiono w poniższej tabeli:

Nagłówek
- Dane globalne
- Opis 1. kolumny
- Opis 2. kolumny
- ...
- Opis ostatniej kolumny
Obszar danych
- Rekord 1 (1. kolumny, 2. kolumny, ... ostatniej kolumny)
- Rekord 2 (1. kolumny, 2. kolumny, ... ostatniej kolumny)
- ...
- Ostatni rekord


Dane globalne

Dane te zawierają informacje o pliku: Istniejące pozycje Memo, data ostatniej aktualizacji, ilość rekordów, rozmiar nagłówka itd.. Dane te są zawarte w pierwszych 32 bajtach pliku bazy danych. Dokładny opis znajduje się w poniższej tabeli:
 
Początek Ilość bajtów Notatka
1 1 Znacznik pliku DBF + istnienie pozycji Memo (#3 - nie, #131 - tak)
2 1 Rok ostatniej aktualizacji pliku
3 1 Miesiąc ostatniej aktualizacji pliku
4 1 Dzień ostatniej aktualizacji pliku
5 4 Całkowita ilość rekordów w pliku
9 2 Rozmiar nagłówka pliku bazy danych
11 2 Rozmiar jednego rekordu
13 20 Zarezerwowane dla niestandardowych danych różnych aplikacji


Opis kolumny

W tej sekcji znajdują się informacje dotyczące jednej kolumny rekordu: na przykład typ pozycji w kolumnie, długość pozycji w kolumnie, lokalizacja pozycji w kolumnie itd. Opis każdej pozycji w kolumnie zajmuje dokładnie 32 bajty. Podstawowe typy kolumn to:

- Char - łańcuch
- Date - data
- Logical - do zapisu tak/nie
- Memo - notatka
- Numeric - liczba
Blok opisu pozycji:
 
Początek Ilość bajtów Notatka
1 11 Nazwa pozycji kolumny
12 1 Typ pozycji kolumny - C (Char), D (Date), L (Logical), M (Memo), N (Numeric)
13 1 Lokalizacja pozycji kolumny
17 1 Długość pozycji kolumny
18 4 Ilość miejsc dziesiętnych (dla typu N)
19 2 Zarezerwowane


Jak pracować z tablicą przy pomocy obiektu PmBuffer.

W pierwszej kolejności należy odczytać nagłówek pliku bazy danych i przetworzyć poszczególne dane. Prawdopodobnie najłatwiej jest wczytać nagłówek do tablicy rekordów. Typ rekordu powinien mieć strukturę opisu pozycji w rekordzie. W ten sposób uzyskuje się niezbędne informacje o pozycjach w rekordzie. Z rozmiaru nagłówka można łatwo wywnioskować, gdzie znajduje się pierwszy rekord. Ponieważ rekordy mają ten sam rozmiar, każdy rekord w pliku można znaleźć za pomocą prostego "adresu": Rozmiar_nagłówek + N x Rozmiar_rekordu.

Ważne jest, aby wszystkie typy elementów były zapisane jako łańcuch, tzn. string.
Char - zapisany jako sekwencja ASCII, o maksymalnej długości 256 znaków
Data - zapisywana jest w formacie RRRRMMDD, rok podawany jest w całości
Logiczne - zapisane jako "T" prawda, "F" fałsz, długość tego pola wynosi zawsze 1
Numeryczne - zapisywane jako rzeczywiste, długość liczby oraz ilość miejsc po przecinku można znaleźć w opisie pozycji w nagłówku pliku
Memo - pominięte


Jeżeli chcesz oznaczyć rekord jako usunięty, wtedy można to zrobić, nadpisując pierwszy bajt rekordu znakiem #42. Zapis ten można przywrócić, nadpisując pierwszy bajt znakiem #32. Nowe rekordy są zapisywane na końcu pliku, pamiętając, aby po ostatnim rekordzie zapisać znacznik końca pliku. Po zakończeniu pracy z plikiem bazy danych zaleca się aktualizację nagłówka pliku (wysłane modyfikacje, ilość rekordów itd.).
 
Przykład, który umożliwia wytworzenie, edycję i zapis do pliku tabeli w formacie dbf przy pomocy obiektu PmBuffer.:
Ta część skryptu zawiera funkcje główne i pomocnicze do pracy z tabelką.
 
Następne przykłady pokazują, jak używać tych funkcji w tabeli testowej.
JavaScriptWybierz oraz skopiuj do schowka

var oBuf, aColsInfo, nHeadSize, nCountRec, nRowSize, aValues, i, j;

function DbfCreateHeadInfo()
{
oBuf = Pm.CreatePmBuffer();
var d = Pm.CreatePmDateObject();
oBuf.SetUint8(-2, 3);   // Memo (#3)
oBuf.SetInt8(-2, d.GetYear());   // Year last updated
oBuf.SetInt8(-2, d.GetMonth());   // Month last updated
oBuf.SetInt8(-2, d.GetDay());   // Day last updated
oBuf.SetInt32(-2, 0);   // Total number of records
oBuf.SetInt16(-2, 0);   // Header size (nCol * 32 + 32 + 1)
oBuf.SetInt16(-2, 0);   // Size of one record (sum of "Item length" of each column + 1)
oBuf.SetStringFix(-2, null, 20, 0, 0);   // reserve
}

function DbfAddColumn(sTitle, sType, nLong, nDec)
{
nHeadSize = oBuf.GetInt16(8);
nRowSize = oBuf.GetInt16(10);
var nCol = (nHeadSize == 0) ? 1 : (nHeadSize - 1) / 32;
if (nCol > 1)
{
var nSize = oBuf.GetSize();
oBuf.SetSize(nSize -2, 1);
}
oBuf.SetStringFix(-2, sTitle, 11, 0, 0);   // Item name
oBuf.SetStringFix(-2, sType, 1, 0, 0);   // Type - C (Char), D (Date), L (Logical), M (Memo), N (Numeric)
oBuf.SetInt32(-2, 0);   // Position of the item
oBuf.SetInt8(-2, nLong);   // Item length
oBuf.SetInt8(-2, nDec);   // Number of decimal places (for type N)
oBuf.SetStringFix(-2, null, 14, 0, 0);   // reserve
oBuf.SetStringFix(-2, null, 2, 0, 0);
oBuf.SetInt16(8, nCol * 32 + 33);
oBuf.SetInt16(10, (nRowSize == 0) ? nLong + 1 : nRowSize + nLong);
}

function DbfGetColumnInfo()
{
oBuf.AutoOffset = 0;
nCountRec = oBuf.GetInt32(4);
nHeadSize = oBuf.GetInt16(8);
oBuf.AutoOffset = 32;
var nCols = (nHeadSize - 1 - 32) / 32;
aColsInfo = Pm.CreatePmArray().Create(nCols, 5);
for (i = 0; i < nCols; i++)
{
aColsInfo.SetItem(oBuf.GetStringFix(-4, 11, 0), i, 0);   // Column - item name
aColsInfo.SetItem(oBuf.GetStringFix(-4, 1, 0), i, 1);   // Column - Type - C (Char), D (Date), L (Logical), M (Memo), N (Numeric)
aColsInfo.SetItem(oBuf.GetInt32(-4), i, 2);   // Column - position of the item
aColsInfo.SetItem(oBuf.GetInt8(-4), i, 3);   // Column - item length
aColsInfo.SetItem(oBuf.GetInt8(-4), i, 4);   // Column - number of decimal places (for type N)
oBuf.GetStringFix(-4, 14, 0);   // Reserve
}
oBuf.GetStringFix(-4, 2, 0);
}

function DbfAddRow(aValues)
{
DbfGetColumnInfo();
var nCols = aValues.GetSize(1);
for (j = 0; j < nCols; j++)
{
var nS = Pm.ToNumber(aColsInfo.GetItem(j, 3));
switch (aColsInfo.GetItem(j, 1))
{
case "D":   // D (Date)
var oFmt = Pm.CreatePmFormat("Len:8;");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(-2, Val, nS, 0, 0);
break;
case "L":   // L (Logical)
var Val = aValues.GetItem(j);
if (Val == "T" || Val == "F")
{
oBuf.SetStringFix(-2, Val, nS, 0, 0);
}
else if (Val == "true" || Val == "false")
{
oBuf.SetStringFix(-2, Val == "true" ? "T" : "F", nS, 0, 0);
}
else
{
oBuf.SetStringFix(-2, Pm.ToNumber(Val) ? "T" : "F", nS, 0, 0);
}
break;
case "N":   // N (Numeric)
var nDec = aColsInfo.GetItem(j, 4);
var oFmt = Pm.CreatePmFormat("Type:Float;Len:" + nS + ";DLen:" + nDec + ";");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(-2, Val, nS, 0, 0);
break;
default:
var oFmt = Pm.CreatePmFormat("Type:String;Len:" + nS + ";IfShort:2;IfLong:2;");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(-2, Val, nS, 0, 0);
break;
}
}

oBuf.SetStringFix(-2, null, 1, 0, 0);
nCountRec = nCountRec + 1;
DbfSetHeadInfo();
}

function DbfSetHeadInfo()
{
var oDate = Pm.CreatePmDateObject();
oBuf.AutoOffset = 0;
oBuf.GetInt8(4);
oBuf.SetInt8(4, oDate.GetYear() -2000);   // Year 22, 23, ...
oBuf.SetInt8(4, oDate.GetMonth());   // Month
oBuf.SetInt8(4, oDate.GetDay());   // Day
oBuf.SetInt32(4, nCountRec);
}

function DbfGetData(bTitle)
{
DbfGetColumnInfo();
var nRows = bTitle ? nCountRec + 1 : nCountRec;
var nCols = aColsInfo.GetSize(1);
var aData = Pm.CreatePmArray().Create(nRows, nCols);
var nS, Val;
var nTitle = 0;
if (bTitle)
{
nTitle = 1;
for (j = 0; j < nCols; j++)
{
aData.SetItem(aColsInfo.GetItem(j, 0), 0, j);
}
}
for (i = 0; i < nRows; i++)
{
for (j = 0; j < nCols; j++)
{
nS = Pm.ToNumber(aColsInfo.GetItem(j, 3));
Val = oBuf.GetStringFix(-4, nS, 0);
switch (aColsInfo.GetItem(j, 1))
{
case "N":
Val = Pm.ToNumber(Val);
break;
case "L":
Val = (Val == "F") ? false : true;
break;
default:
break;
}
aData.SetItem(Val, i + nTitle, j);
}
oBuf.GetStringFix(-4, 1, 0);
}
return aData;
}

function DbfFindValue(sColName, FindVal)
{
DbfGetColumnInfo();
var nOffset = oBuf.AutoOffset;
nRowSize = oBuf.GetInt16(10);
var nCols = (nHeadSize -1 -32) / 32;
var nColSearch;
var nPozVal = 0;
var nRec = 1;

for (i = 0; i < nCols; i++)
{
if (sColName == aColsInfo.GetItem(i, 0))
{
nColSearch = i;
break;
}
nPozVal = nPozVal + Pm.ToNumber(aColsInfo.GetItem(i, 3));
}

var nS = Pm.ToNumber(aColsInfo.GetItem(nColSearch, 3));
for (i = 0; i < nCountRec; i++)
{
var Val = oBuf.GetStringFix(nOffset + nPozVal, nS, 0);
if (Val == FindVal)
{
break;
}
nPozVal = nPozVal + nRowSize;
}
return i;
}

function DbfEditRow(nRowEdit, aValues)
{
DbfGetColumnInfo();
var nOffset = oBuf.AutoOffset;
nRowSize = oBuf.GetInt16(10);
var nPoz = nOffset + (nRowSize * nRowEdit);
var nCols = aValues.GetSize(1);

for (j = 0; j < nCols; j++)
{
var nS = Pm.ToNumber(aColsInfo.GetItem(j, 3));
switch (aColsInfo.GetItem(j, 1))
{
case "D":   // D (Date)
var oFmt = Pm.CreatePmFormat("Len:8;");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(nPoz, Val, nS, 0, 0);
break;
case "L":   // L (Logical)
var Val = aValues.GetItem(j);
if (Val == "T" || Val == "F")
{
oBuf.SetStringFix(nPoz, Val, nS, 0, 0);
}
else if (Val == "true" || Val == "false")
{
oBuf.SetStringFix(nPoz, Val == "true" ? "T" : "F", nS, 0, 0);
}
else
{
oBuf.SetStringFix(nPoz, Pm.ToNumber(Val) ? "T" : "F", nS, 0, 0);
}
break;
case "N":   // N (Numeric)
var nDec = aColsInfo.GetItem(j, 4);
var oFmt = Pm.CreatePmFormat("Type:Float;Len:" + nS + ";DLen:" + nDec + ";");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(nPoz, Val, nS, 0, 0);
break;
default:
var oFmt = Pm.CreatePmFormat("Type:String;Len:" + nS + ";IfShort:2;IfLong:2;");
var Val = oFmt.Format(aValues.GetItem(j));
oBuf.SetStringFix(nPoz, Val, nS, 0, 0);
break;
}
nPoz = nPoz + nS;
}
}

function DbfSaveToFile(sFile)
{
oBuf.SaveToFile(0, "#data:" + sFile, 0, -1);   // save to dbf file
}

function DbfLoadFromFile(sFile)
{
oBuf = Pm.CreatePmBuffer();
oBuf.LoadFromFile(-2, "#data:" + sFile, 0, -1);
oBuf.AutoOffset = 0;
}
Przykład2:
Przykład tworzenia nowej tabeli z pięcioma kolumnami i trzema pierwszymi rekordami, która jest zapisywana do pliku o nazwie "Test.dbf" do foldera Data w aplikacji
JavaScriptWybierz oraz skopiuj do schowka

// -------------------- Create dBase table --------------------------
var aValues;
DbfCreateHeadInfo();
// AddColumn(sTitle, sType, nLong, nDec)
DbfAddColumn("Test", "C", 9, 0);   // 1 column
DbfAddColumn("State", "L", 1, 0);   // 2 column
DbfAddColumn("ValD", "N", 12, 2);   // 3 column
DbfAddColumn("ValN", "N", 10, 0);   // 4 column
DbfAddColumn("Note", "C", 40, 0);   // 5 column

aValues = Pm.CreatePmArray().Array1("Test1", true, 45786.21, 786, "Note1");
DbfAddRow(aValues);

aValues = Pm.CreatePmArray().Array1("Test2", false, 3333.33, 4568, "Note2");
DbfAddRow(aValues);

aValues = Pm.CreatePmArray().Array1("Test3", true, 4567.45, 72, "Note3");
DbfAddRow(aValues);

DbfSaveToFile("Test.dbf");
Przykład3:
Przykład pozwalający uzyskać dwuwymiarową tablicę wszystkich rekordów w tabeli. Parametr metody "DbfGetData" określa, czy nazwy kolumn są również częścią tablicy danych.
JavaScriptWybierz oraz skopiuj do schowka

// ----------------- Get all records -------------------------
DbfLoadFromFile("Test.dbf");
var aData = DbfGetData(true);   // (true/false) yes/no column names
Pm.Debug(aData);
Przykład4:
Przykład dodawania dodatkowych rekordów na końcu istniejącej tabeli.
JavaScriptWybierz oraz skopiuj do schowka

// ----------------- Add Record -------------------------
DbfLoadFromFile("Test.dbf");

aValues = Pm.CreatePmArray().Array1("Test4", false, 17.33, 111, "Test");
DbfAddRow(aValues);

aValues = Pm.CreatePmArray().Array1("Test5", true, 0.29, 10, "Note5");
DbfAddRow(aValues);

aValues = Pm.CreatePmArray().Array1("Test6", true, 75.5, 21, "Note6");
DbfAddRow(aValues);

aValues = Pm.CreatePmArray().Array1("Test7", true, 487.53, 20, "Note7");
DbfAddRow(aValues);

DbfSaveToFile("Test.dbf");
Przykład5:
Przykład wyszukuje wartość "Test4" w kolumnie "Test" i zwraca numer wiersza tego rekordu. Następnie metoda "DbfEditRow" edytuje wartości rekordu w tym znalezionym wierszu.
JavaScriptWybierz oraz skopiuj do schowka

// ----------------- Search record and change values -------------------------
DbfLoadFromFile("Test.dbf");

var nRow = DbfFindValue("Test", "Test4");
// var nRow = DbfFindValue("ValD", 17.33);
DbfEditRow(nRow, Pm.CreatePmArray().Array1("Test4", true, 17.33, 111, "Note4"));

DbfSaveToFile("Test.dbf");
Patrz również:
© MICROSYS, spol. s r. o.