在C#中生成PDB文件
本文展示了如何创建 .pdb 文件,以便在 Palm 设备上用作数据库。
Palm 数据库的基础知识
Palm 设备使用两种类型的数据库文件:PRC 和 PDB(即.prc 和 .pdb)。PRC 用于 Palm OS 数据库,它是应用程序,并存储应用程序的资源,而 PDB(Pilot 数据库)用于仅包含数据的 Palm OS 数据库。这两种数据库都有一个唯一的密钥,每个应用程序都是唯一的。这些数据库可以像流读取和流写入一样进行操作。它包含一个名为“备份位”的属性位。设置此位表示没有自定义导管将备份数据库,并且应该在 HotSync 过程中备份数据库。如果在 Palm Pilot 上创建数据库并设置了“备份位”,则会在执行 HotSync 的计算机上的Backup目录中找到 PDB 格式的数据库副本。
此应用程序读取 CSV 或 XML 文件,并创建一个 .pdb 文件。
PDB 文件的主要部分
PDB 文件格式包含三个部分
- 头部部分
- 记录列表部分
- 数据列表部分
i. 头部部分
头部部分包含 78 个字节,包含数据库的名称和其他信息。此外,还包含对应用程序唯一的数据库 ID(该 ID 是全局唯一的,可以从 Palm OS 站点获得)、数据库的类型和其他属性。 PDBHeader
类用于创建头部。
class PDBHeader
{
#region Declarations
char[] databaseName={'\0','\0','\0','\0','\0','\0','\0',
'\0','\0','\0','\0','\0','\0','\0','\0',
'\0','\0','\0','\0','\0','\0','\0','\0',
'\0','\0','\0','\0','\0','\0','\0',
'\0','\0'}; // 32 Bytes
UInt16 fileAttributes = 0X0008; // 2 Bytes
UInt16 version = 0X0000; // 2 Bytes
UInt32 creationDate; // 4 Bytes
UInt32 modificationDate; // 4 Bytes
UInt32 lastBackupDate; // 4 Bytes
UInt32 modification=0X0000; // 4 Bytes
UInt32 appInfoArea=0X0000; // 4 Bytes
UInt32 sortInfoArea=0X0000; // 4 Bytes
char[] type={'d','a','t','a'}; // 4 Bytes
char[] creatorID; // 4 Bytes
UInt32 uniqueID=0X0000; // 4 Bytes
UInt32 nextRecord=0X0000; // 4 Bytes
UInt16 numRecords; // 2 Bytes
#endregion
#region Properties
public UInt16 NumRecords
{
set
{
numRecords=value;
}
get
{
return numRecords;
}
}
public DateTime CreationDate
{
set
{
TimeSpan ts=DateTime.Now-value;
creationDate=(UInt32)ts.TotalSeconds;
}
}
public DateTime ModificationDate
{
set
{
TimeSpan ts=DateTime.Now-value;
modificationDate=(UInt32)ts.TotalSeconds;
}
}
public DateTime LastBackupDate
{
set
{
TimeSpan ts=DateTime.Now-value;
lastBackupDate=(UInt32)ts.TotalSeconds;
}
}
public string CreatorID
{
set
{
if (value.Length==4)
{
creatorID=value.ToCharArray();
}
else
{
throw new PDBException("Creator ID" +
" is invalid (must be 4 charactors)");;
}
}
get
{
return new String(creatorID);
}
}
public string DataBaseName
{
set
{
if (value.Length<=32)
{
databaseName=value.ToCharArray();
}
else
{
throw new PDBException("Database Name" +
" Exceeds 32 Charactors");;
}
}
get
{
return new String(databaseName);
}
}
#endregion
#region Functions
public PDBHeader()
{
// Palm databse store total number
// of seconds since 01-01-1904
TimeSpan ts=
DateTime.Now-DateTime.Parse("01-01-1904");
creationDate=(UInt32)ts.TotalSeconds;
modificationDate=(UInt32)ts.TotalSeconds;
lastBackupDate=(UInt32)ts.TotalSeconds;
numRecords=0;
}
public override string ToString()
{
string getAll="";
getAll+=HexEncoding.GetStringToChar(databaseName,32);
getAll+=fileAttributes.ToString("X4");
getAll+=version.ToString("X4");
getAll+=creationDate.ToString("X8");
getAll+=modificationDate.ToString("X8");
getAll+=lastBackupDate.ToString("X8");
getAll+=modification.ToString("X8");
getAll+=appInfoArea.ToString("X8");
getAll+=sortInfoArea.ToString("X8");
getAll+=HexEncoding.GetStringToChar(type,4);
getAll+=HexEncoding.GetStringToChar(creatorID,4);
getAll+=uniqueID.ToString("X8");
getAll+=nextRecord.ToString("X8");
getAll+=numRecords.ToString("X4");
return getAll;
}
ii. 记录列表部分
记录列表部分的大小取决于记录的数量。每个记录使用 8 位来存储记录信息。 PDBRecordList
类用于表示记录列表。
class PDBRecordList
{
#region Declarations
UInt32 offset=0; // 4 Bytes (Offset of the record)
byte recordAttribute=0X40;
char[] uniqueID={'\0','\0','\0'}; // 3 Bytes (Unique ID for each record)
string dataRecord=""; // Record data for current record
#endregion
#region Properties
public string DataRecord
{
set
{
dataRecord=value;
}
get
{
return dataRecord;
}
}
public UInt32 RecordOffset
{
set
{
offset=value;
}
get
{
return offset;
}
}
#endregion
#region Functions
public PDBRecordList(string str)
{
dataRecord=str;
}
public override string ToString()
{
string getAll="";
getAll+=offset.ToString("X8");
getAll+=recordAttribute.ToString("X2");
getAll+=HexEncoding.GetStringToChar(uniqueID,3);
return getAll;
}
#endregion
}
iii. 数据部分
它是存储与记录相关的信息的主要部分。每条记录都以空终止字符('\0')分隔。每个记录的大小可能不同,但列数应相同。
使用代码
PDBCreators
类用于创建数据库。
class PDBCreators
{
PDBHeader header=new PDBHeader();
ArrayList pdbRecord=new ArrayList();
public PDBCreators()
{
}
public PDBHeader PDBHeaders
{
set
{
header=value;
}
get
{
return header;
}
}
public Object[] AddRecord
{
set
{
string row="";
for (int i=0; i<value.Length; i++)
{
if (value[i].GetType().ToString()=="System.Int32")
continue;
row+=value[i].ToString().Trim()+'\0';
}
pdbRecord.Add(new PDBRecordList(row));
}
}
public void GeneratePDB(string fileName)
{
try
{
FileStream fs=new FileStream(fileName,FileMode.Create);
BinaryWriter bw=new BinaryWriter(fs);
int discard=0;
UInt32 index=78; // Header length is 78 Bytes
header.NumRecords=(UInt16)pdbRecord.Count;
bw.Write(HexEncoding.GetBytes(header.ToString(),
out discard));
// start index of Data List Area
index+=(UInt32)(pdbRecord.Count*8)+2;
string result="";
for (int i=0; ipdbRecord.Count; i++)
{
PDBRecordList rec=(PDBRecordList)pdbRecord[i];
rec.RecordOffset=index;
bw.Write(HexEncoding.GetBytes(rec.ToString(),
out discard));
index+=(UInt32)rec.DataRecord.Length;
result+=rec.DataRecord;
}
char[] padding={'\0','\0'}; // Two bytes for backup bits
bw.Write(HexEncoding.GetBytes(
HexEncoding.GetStringToChar(padding,2),
out discard));
result=HexEncoding.GetStringToChar(
result.ToCharArray(),result.Length);
bw.Write(HexEncoding.GetBytes(result,out discard));
bw.Close();
fs.Close();
}
catch (Exception exc)
{
throw new PDBException("Error" +
" in writing pdb file "+exc.Message);
}
}
}
PDBGenerator
读取两种文件格式(CSV 和 XML),并在 DataGrid
中以表格格式显示数据。可以更改此数据。它从 XML 文件中读取所有表格数据,并在组合框中显示表格名称。
PDBCreators pdb=new PDBCreators();
pdb.PDBHeaders.DataBaseName=this.txtDBName.Text;
pdb.PDBHeaders.CreatorID=this.txtCreatorID.Text;
DataTable recordsTable;
if (recordsDataSet.Tables.Count>0 &&
this.cmbTableNames.Items.Count>0 &&
recordsDataSet.Tables.Contains(this.cmbTableNames.Text))
recordsTable=recordsDataSet.Tables[this.cmbTableNames.Text];
else
{
MessageBox.Show("There is no table to convert",
"PDB Generator",MessageBoxButtons.OK,
MessageBoxIcon.Information);
return;
}
for (int i=0; i<recordsTable.Rows.Count; i++)
pdb.AddRecord=recordsTable.Rows[i].ItemArray;
try
{
pdb.GeneratePDB(this.txtDestination.Text+"\\"+
this.txtDBName.Text+".pdb");
MessageBox.Show("PDB Generated Successfully",
"PDB Generator",MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch(Exception exc)
{
MessageBox.Show("Error in PDB Generation"+exc.ToString(),
"PDB Generator",MessageBoxButtons.OK,
MessageBoxIcon.Information);
}