Promotic

Struktura souboru dBase III.

Datový soubor typu .dbf má přesně definovanou strukturu. Skládá se z hlavičky a bloku dat. Samotná hlavička se skládá z globálních údajů popisující dbf soubor a ze seznamu, ve kterém je zahrnuty popisy jednotlivých položek v databázovém souboru. Za tímto seznamem (a tedy už koncem hlavičky) následuje datová oblast, kde jsou za sebou 1. záznam, 2. záznam, ... až poslední záznam v databázovém souboru. Všechny záznamy mají stejnou délku. Strukturu zobrazuje následující tabulka:

Hlavička
- Globální údaje
- Popis 1. sloupce
- Popis 2. sloupce
- ...
- Popis posledního sloupce
Datová oblast
- Záznam 1 (1. sloupce, 2. sloupce, ... posl. sloupce)
- Záznam 2 (1. sloupce, 2. sloupce, ... posl. sloupce)
- ...
- Záznam poslední


Globální údaje

V těchto údajích naleznete informace o souboru: existencích Memo položek, datum poslední aktualizace, počet záznamů, velikost hlavičky atd. Tyto údaje jsou obsaženy v prvních 32 bajtech databázového souboru. Přesný popis obsahuje následující tabulka:
 
Začátek Počet bajtů Poznámka
1 1 Značka DBF souboru + existence Memo položek (#3 - ne, #131 - ano)
2 1 Rok poslední aktualizace souboru
3 1 Měsíc poslední aktualizace souboru
4 1 Den poslední aktualizace souboru
5 4 Celkový počet záznamů v souboru
9 2 Velikost hlavičky databázového souboru
11 2 Velikost jednoho záznamu
13 20 Rezervováno pro nestandardní údaje různých aplikací


Popis sloupce

V této části najdete informace týkající se jednoho sloupce záznamu: například typ položky sloupce, délka položky sloupce, jeho poloha atd. Popis položek každého sloupce zabírá právě 32 bajtů. Základní typy sloupců jsou:

- Char - řetězec
- Date - datum
- Logical - pro zápis ano/ne
- Memo - poznámka
- Numeric - číslo
Blok popisu položek:
 
Začátek Počet bajtů Poznámka
1 11 Název položky sloupce
12 1 Typ položky sloupce - C (Char), D (Date), L (Logical), M (Memo), N (Numeric)
13 1 Poloha položky sloupce
17 1 Délka položky sloupce
18 4 Počet deset. míst (pro typ N)
19 2 Rezervováno


Jak pracovat s tabulkou pomocí objektu PmBuffer.

V první řadě je nutno načíst hlavičku databázového souboru a zpracovat jednotlivé údaje. Nejjednodušší je asi načíst hlavičku do pole záznamů. Typ záznamu by měl mít strukturu popisu položky v záznamu. Tím máme potřebné údaje o položkách záznamu. Z velikosti hlavičky můžeme snadno odvodit polohu prvního záznamu. Vzhledem k tomu, že záznamy mají stejnou velikost, lze pak jakýkoliv záznam v souboru nalézt pomocí jednoduché "adresy": Velikost_hlavička + N x Velikost_záznamu.

Důležité je, že všechny typy položek se zapisují ve formě řetězce, tzn. string.
Char - zapisuje se jako posloupnost ASCII, o maximální délce 256 znaků
Date - zapisuje se ve formátu RRRRMMDD, rok je udáván i s letopočtem
Logical - zapisuje se jako "T" true, "F" false, délka tohoto pole je vždy 1
Numeric - zapisuje se jako real, délku čísla a počet desetinných míst zjístíte z popisu položky v hlavičce souboru
Memo - vynechávám


Pokud chcete nějaký záznam označit za zrušený, pak to provedete tak, že první bajt záznamu přepíšete znakem #42. Tento záznam lze obnovit opětovným přepsáním prvního bajtu znakem #32. Nové záznamy se zapisují na konec souboru, přičemž je nutné dodržet psaní značky konce souboru za poslední záznam. Při ukončení práce s databázovým souborem je vhodné aktualizovat hlavičku soubotu (posl. modifikace, počet záznamů atd.)
 
Příklad který umožní pomocí objektu PmBuffer vytvořit, editovat a uložit do souboru tabulku ve formátu dbf.:
V této části skriptu jsou hlavní a pomocné funkce pro práci s tabulkou.
 
A v následujících přikladech jsou ukázky použití těchto funkcí nad testovací tabulkou.
JavaScriptVyber a zkopíruj do schránky

var oBuf, aColsInfo, nHeadSize, nCountRec, nRowSize, aValues, iRow, iCol;

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 (iCol = 0; iCol < nCols; iCol++)
{
aColsInfo.SetItem(oBuf.GetStringFix(-4, 11, 0), iCol, 0);   // Column - item name
aColsInfo.SetItem(oBuf.GetStringFix(-4, 1, 0), iCol, 1);   // Column - Type - C (Char), D (Date), L (Logical), M (Memo), N (Numeric)
aColsInfo.SetItem(oBuf.GetInt32(-4), iCol, 2);   // Column - position of the item
aColsInfo.SetItem(oBuf.GetInt8(-4), iCol, 3);   // Column - item length
aColsInfo.SetItem(oBuf.GetInt8(-4), iCol, 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 (iCol = 0; iCol < nCols; iCol++)
{
var nS = Pm.ToNumber(aColsInfo.GetItem(iCol, 3));
switch (aColsInfo.GetItem(iCol, 1))
{
case "D":   // D (Date)
var oFmt = Pm.CreatePmFormat("Len:8;");
var Val = oFmt.Format(aValues.GetItem(iCol));
oBuf.SetStringFix(-2, Val, nS, 0, 0);
break;
case "L":   // L (Logical)
var Val = aValues.GetItem(iCol);
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(iCol, 4);
var oFmt = Pm.CreatePmFormat("Type:Float;Len:" + nS + ";DLen:" + nDec + ";");
var Val = oFmt.Format(aValues.GetItem(iCol));
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(iCol));
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 (iCol = 0; iCol < nCols; iCol++)
{
aData.SetItem(aColsInfo.GetItem(iCol, 0), 0, iCol);
}
}
for (iRow = 0; iRow < nRows; iRow++)
{
for (iCol = 0; iCol < nCols; iCol++)
{
nS = Pm.ToNumber(aColsInfo.GetItem(iCol, 3));
Val = oBuf.GetStringFix(-4, nS, 0);
switch (aColsInfo.GetItem(iCol, 1))
{
case "N":
Val = Pm.ToNumber(Val);
break;
case "L":
Val = (Val == "F") ? false : true;
break;
default:
break;
}
aData.SetItem(Val, iRow + nTitle, iCol);
}
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 (iCol = 0; iCol < nCols; iCol++)
{
if (sColName == aColsInfo.GetItem(iCol, 0))
{
nColSearch = iCol;
break;
}
nPozVal = nPozVal + Pm.ToNumber(aColsInfo.GetItem(iCol, 3));
}

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

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

for (iCol = 0; iCol < nCols; iCol++)
{
var nS = Pm.ToNumber(aColsInfo.GetItem(iCol, 3));
switch (aColsInfo.GetItem(iCol, 1))
{
case "D":   // D (Date)
var oFmt = Pm.CreatePmFormat("Len:8;");
var Val = oFmt.Format(aValues.GetItem(iCol));
oBuf.SetStringFix(nPoz, Val, nS, 0, 0);
break;
case "L":   // L (Logical)
var Val = aValues.GetItem(iCol);
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(iCol, 4);
var oFmt = Pm.CreatePmFormat("Type:Float;Len:" + nS + ";DLen:" + nDec + ";");
var Val = oFmt.Format(aValues.GetItem(iCol));
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(iCol));
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;
}
Příklad2:
Příklad pro vytvoření nové tabulky s pěti sloupci a se třemi prvními záznamy, která se uloží do souboru s názvem "Test.dbf" do složky "Data" v aplikaci
JavaScriptVyber a zkopíruj do schránky

// -------------------- 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.Array1("Test1", true, 45786.21, 786, "Note1");
DbfAddRow(aValues);

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

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

DbfSaveToFile("Test.dbf");
Příklad3:
Příklad pro získání 2-rozměrného pole všech záznamů v tabulce. Parametr metody "DbfGetData" určuje zda součástí pole dat budou také názvy sloupců.
JavaScriptVyber a zkopíruj do schránky

// ----------------- Get all records -------------------------
DbfLoadFromFile("Test.dbf");
var aData = DbfGetData(true);   // (true/false) yes/no column names
Pm.Debug(aData);
Příklad4:
Příklad pro přidání dalších záznamů na konec existující tabulky.
JavaScriptVyber a zkopíruj do schránky

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

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

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

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

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

DbfSaveToFile("Test.dbf");
Příklad5:
Příklad vyhledá ve sloupci "Test" hodnotu "Test4" a vrátí číslo řádku tohoto záznamu. Na tomto nalezeném řádku pak metoda "DbfEditRow" provede editaci hodnot záznamu.
JavaScriptVyber a zkopíruj do schránky

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

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

DbfSaveToFile("Test.dbf");
© MICROSYS, spol. s r.o.