How to read and write dbf in a native way? - delphi

In Delphi for Win32, how to read and write a dbf file in a native way, without the BDE? I know there are some components available in the web, but I have never used any of them, so I don't know which to choose (if any).

You can use ADO to access a DBF File
See ths sample code (using an TAdoConnection and TAdoDataSet components).
var
dbf_folder : string;
begin
dbf_folder:='c:\bdd';//set your dbf folder location here
ADOConnection1.LoginPrompt:=false;
ADOConnection1.ConnectionString:=Format('Provider=Microsoft.JET.OLEDB.4.0;Data Source=%s;Extended Properties=dBase IV;',[dbf_folder]);
try
ADOConnection1.Connected:=True;
ADODataSet1.CommandText:='Select * from file.dbf'; //make your SQL query using the name of the dbf file
ADODataSet1.Open;
while not ADODataSet1.eof do
begin
//do your stuff here
//ADODataSet1.FieldByName('').AsString
ADODataSet1.Next;
end;
except
on E : Exception do
ShowMessage(E.Message);
end;
end;

I used TDBF back when I was still working with DBF files (some legacy apps). I still use it for maintainance of those apps here and there. It is free, has a lot of features and works good.

I used Topaz from Software Science for many years before I got started with Firebird. It was always an excellent library, had a terrific manual and good technical support. It supports indexes and even has an in-memory option. I think it would be a good choice.

Apollo Database VCL.

ADO didn't work for me but I managed to open my dbf file using BDE:
From a Data Access (or BDE, depends on your version of Delphi) section I put a TDataBase and, TTable components (you can use TQuery if you want).
By doubleclick on TDataBase component I opened the setup dialog. Filled the Name field with 'db_name' (the name is arbitrary), driver name = 'STANDARD', Parameters field: 'PATH=C:\Path\To\DBF_FILES\'.
Then I set Connected=True.
Then in TTable component I set DatabaseName = 'db_name' - the one I set in TDataBase component. And TableName property set 'DB_FILE.dbf' which was located in the specified folder.
Active = True.
You know what to do next

It is not hard to read a DBF file if you don't need indexes. The format is pretty straightforward. A header followed for fixed sized registers. There is a flag in each register which indicates if it is deleted or not. I suggest looking for a component which does what you want. You can find some in Torry's Delphi pages.

Related

How to treat non design component initialization errors?

For start, lets take an exemplification:
You create a new VCL application project in Delphi and put a TIBDataBase and type in the path and name of the database file with the extension .IB ok?
Now, If you you just put example.ib and leave the path behind, when you execute your application without Delphi, it will open the database normally if the .EXE is in the same path as the .IB but if you run your application from Delphi, it will raise an error because it can't find the database file, because Delphi changes the working directory.
Sometimes you want to leave the Active property of that component set to True while you are developing, and them set to False and change it during the start of the application, when you deliver to your client. All that because he/she may want to install in a different path and your application has to find the proper place of the database before open it.
The problem comes when you already delivered to your client and still make some changes everyday on the code. You then have to deploy at least once a day, and sometime you just forget to set that property back to False and when the client receives the update and tries to run it, he/she gets a not found database error.
The question is, how can I handle that error if this opening happens automatically when the component is loaded in memory and the activation of the database does not happens in my own code?
I do not think you are going to find a general solution to preventing run time exceptions from design time property settings without modifying the component or deriving a descendent.
For TIBDatabase, set the property AllowStreamedConnected to False. This stops TIBDataBase from automatically connecting to the database at run time when Connected is True at design time. TIBQuery using this TIBDatabase will not open even it is set Active at design time.
Some other database connection components have similar properties.
Regarding the database issue only: if I understand you correctly, my solution requires you to write an event handler for the 'BeforeConnect' event as shown below:
procedure TDM.SQLConnection1BeforeConnect(Sender: TObject);
var
dir: string;
begin
with TRegIniFile.create (regpath) do // I keep my database locations in the registry
begin // but you can use any method of getting the location
dir:= ReadString ('firebird', progname, '');
free
end;
with sqlconnection1 do
begin
close;
params.values['database']:= dir;
loginprompt:= false;
end;
end;
This way, you can have one location stored in your database for local use, but have different locations for different users.

How can I create a D-Base IV table using Delphi ADO components please?

I am working on the software for an instrument that logs batch results into single DBase 4 (*.dbf) disk files in a folder. In preparation for adding new logging analysis capability which is planned to work with multiple of these DBF files, I am changing the existing simple BDE TTable and CreateTable which reopen and create a new DBF file respectively into use of the Delphi ADO components.
Using other suggestion here on SO I have successfuly created a test application which opens an existing DBF file using the following core code using a TAdoDataSet and a TAdoConnection:
ADODataSet1.DisableControls;
try
S := ExtractFileDir( ParamStr(0) ); //set the dbf folder location here
ADOConnection1.LoginPrompt:=false;
ADOConnection1.ConnectionString:=Format('Provider=Microsoft.JET.OLEDB.4.0;Data Source=%s;Extended Properties=dBase IV;',[S]);
ADOConnection1.Connected:=True;
ADODataSet1.CommandText:='Select * from test.dbf'; //The SQL query uses the name of the dbf file
ADODataSet1.Open;
finally
AdoDataSet1.EnableControls;
end;
This works fine but before my DBF is used for the first time I will also need to creat an empty DBF file ready to add my log records. I could do this by opening an exising 'empty' DBF file each time but I was hoping that there was an SQL? way of creating my file if I have already created and defined my fields (which is easy for me). I tried this with a TAdoTable where I could created the required fields but I could not find any examples of how to get this table structure out onto disk when nothing was already there, mainly because there are so many ADO examples but almost always working on existing data tables.
Can anyone help me create a sample DFB table file with a couple of fields using ADO components please? I'm sure I can then build on that.
Many Thanks.
Use TADOCommand and execute Create Table SQL, for example something like this :
Create Table Test (TestField1 char(64), TestField2 integer)

GExpert's Replace Components Expert doesn't replace the text in the form file (*.dfm)

I am using Delphi 2010 and GExperts stable release 1.35
I am testing the "Replace Components" expert.
I add a main form and a secondary form. Each has three TEdits on it.
I use the Replace Components Expert to replace all TEdits with TRzEdit. I Check the Replace all components on all forms of the project.
It works, it replaces them all. However, it doesn't do anything to the DFM file. How do i make it replace those instances.
If i save, compile, or rebuild, i get errors.
If i try to view the form as text after replacing, i get errors.
Can someone explain to me the steps to make this work?
Thanks
I just tried it with Delphi XE and GExperts 1.35 and it does indeed crash now even after a single "Replace Selected". (It used to work fine in the past).
It seems that using the hidden menu Project | Clear Unit Cache just after Replace Components then doing a full build before trying any Save/Compile/View As Text... fixes the problem.
I think this menu is surfaced with cnPack. I don't have it and cannot guarantee, but you can easily do it yourself by adding the following unit in one of your installed packages:
unit FGEnableHiddenMenus;
interface
procedure Register;
implementation
uses
Classes, Forms, Menus;
procedure Register;
var
Comp: TComponent;
begin
//Make a hidden menu item visible
Comp := Application.MainForm.FindComponent('ProjectClearUnitCacheItem');
if Comp is TMenuItem then
TMenuItem(Comp).Visible := True;
end;
end.
Source: Brian Long's old goodies
Update:
I had to replace a couple of TEdit by TDBEdit on our main project at work and this trick worked.
But on a new Project with 3 Forms, it failed consistently to write/commit/save the changes on the last Form (same environment).
FYI, I tried with and without DDevExtensions 2.5 and IDEFixPack 4.6.1
Update2:
Went digging in the GExperts forum as suggested by Ulrich and finally found a possible explanation. The new property Touch does not like being copied from one component to another when the source is destroyed (causing the AV).
The suggested workaround is to do a bidirectional mapping in the Expert Settings to disable the copy for this property:
You might be running into this bug while trying to copy the Touch property from the old to the new component, but it has a workaround you can fairly easily test:
http://tech.groups.yahoo.com/group/GExpertsDiscuss/message/3994
Details:
There is a limitation/bug in Delphi 2010 and XE where if you assign a
Component.Touch property from one component to another and destroy the
original component that the new component becomes corrupt (it isn't
like component/interface references, where they either auto-correct
themselves or are reference counted).
For the moment, you can assign a bi-directional replace component
property map from TPanel.Touch to TGroupBox.Touch (use the two components being replaced in your specific case) that is marked as
a disabled property map, and that will work around this problem. Our next release
will not try to assign that property any longer.
GExperts 1.36 is also now available and includes a workaround for this issue. The workaround has been in the GExperts version control system and in testing for several weeks already.

How do I set an attribute on an ODBC connection via DBExpress?

Justification that you might as well skip reading but is included to filter out people telling me not to do something that I'm not sure of in the first place.
I'm trying to debug some multithreaded database hoopla, it's mostly experimental although if I get it working I'd be a very happy guy. I'm very new to DBExpress (only have been using it for 4-5 hours). I'm not using TSQLConnection or any designtime components because I'm trying to rewrite an existing ODBC32.dll interface in a painless an unnoticed way and once I'm done, I'll expose the rest of the awesomeness. The reason I mention this is because it's very apparent that I'm not using dbexpress in the normal way shown in many of the tutorials.
Here's the question
I'm using the TDBXConnection and connecting to an ODBC datasource, I want to try setting the SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE parameter on my connection, but I don't have a clue where to go about setting that particular parameter.
You've got FDBConnection : TDBXConnection; defined somehwere else so now you've got to:
....
begin
if FDBConnection is TDBXOdbcConnection then
with FDBConnection as TDBXOdbcConnection do
begin
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_ENABLE, Pointer(SQL_ASYNC_ENABLE_ON), 0);
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_DBC_FUNCTIONS, Pointer(SQL_ASYNC_DBC_CAPABLE), 0);
end;
end;
That's pretty painless.
Include Data.DBXODBC and System.ODBC in the uses and you're golden.

Form Designer Save and Load

i made a simple form designer in delphi, drag and drop a button on the form and it draws it, but the thing is i cant save/load this project since i dunno how to, is there anyway that i could be abel to save it to .rc file and load it from there?
That depends how you programmed your form designer. In forms created in Delphi's designer all components (and subcomponents) are referenced from TForm.Components array property. All controls are also referenced in TForm.Controls array property (if you remove an container control, all it's subcontrols are destroyed too).
If you have followed that pattern, all you have to do is monitor additions to the TForm.Components array (maybe using an overriden TForm.Notification method) and using this data to build your persistent form's file.
The VCL contains methods for using its builtin DFM support. There is a sample in the Delphi 2009 documentation for ObjectBinaryToText; I guess this works for D7 too. And IIRC there already was a code fragment for ComponentToString in the D5 help - search for ObjectBinaryToText.
Delphi stores form layout in *.dfm file. You can use it's structure to save your projects. File is textual and readable by humans. It is not hard to parse file like that rading one line by one. If you need more help, ask for it.
You can use something like delphi .DFM. Counting all objects and then read their attributes and write them into a file. Example Code:
For i:0 To Form1.ComponentsCount-1 Do Begin
// Read Component Attributes And Write Them In Your Format
End;
If you just want to save the form you designed in your designer, use something like TFileStream to create the RC file when the user saves. You might be better off with your own file format for your forms, with the option to export as an RC file, as RC files arent really meant to useful for storing any design time info you may need.

Resources