⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cdbfile.txt

📁 操纵DBASEIII文件的程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
   * SortAllRecords()  operates a quicksort algorithm on the
      record list. The sorting is done on the criterium   Criter1 , 
      which points to a field descriptor: the list will be sorted in 
      increasing order of the   Criter1  field of the records.
 

  The public functions are in fact a convenient way to embed the private
functions without requiring the user to manipulate those ugly record lists
or structures (yuck!), let alone the field descriptors (ugh!). He just has 
to instantiate a   CDBFile  object in his program, and mind his own business.
All he has to know about how that object works is that there is a special
pointer   CurrentRec  (see above) which points at the record he wants
to access or to modify, and that   CurrentRec  can be moved all along
the list very easily, in an iterative way. Here are the public functions that will 
enable the programmer to do so :

class CDBFile
 
...
public:
  unsigned long LoadFileToMemory();
  unsigned long WriteModified();
  void SortOn(unsigned short Criterium1);
  void GetAtRecord(unsigned long RecordNum) 
       CurrentRec=GetRecord(RecordNum);  
  unsigned long GetRecordNum() 
       if (CurrentRec) return CurrentRec->RecordNumber;
       else return 0L; 
  BOOL GetNextRecord()
       { if (CurrentRec) { CurrentRec=CurrentRec->Next; return TRUE;}
         else return FALSE; }
  BOOL GetPreviousRecord()
       { if (CurrentRec) { CurrentRec=CurrentRec->Previous; return TRUE;}
         else return FALSE; }
  void LoadRecord(unsigned long RecordNum)  
       CurrentRec=ReadRecord(RecordNum); Append(CurrentRec);  
  void DeleteCurrentRec()
       CurrentRec=CurrentRec->Previous; DeleteRecord(CurrentRec->Next); 
  void CreateAndAppend() 
       CurrentRec=CreateNewRecord(); Append(CurrentRec); 
  void ClearAllRecords();		
...
 ;

 
 
  For most of those functions, the souce code is self-explanatory. Some
others are less obvious:   SortOn() , for example, launches the 
recursive quicksort function   SortAllRecords()  (see above). 
  LoadFileToMemory()  reads all the records on the file using 
  ReadRecord()  and stores the resulting records in the list.
  Wri te Mo di fied()  checks all the records in the list and writes some 
of them to the file if they have been edited or modified.
  ClearAllRecords()  empties the list and deletes all the records.
Some more complex functions also involve manipulating the contents of those 
records (  SortAllRecords()  is one of those), or the DBF file. They 
will be explained in the next paragraphs.

     3.4.2 Handling the contents of the records 

We have seen the structure of the records in the previous section; let's 
have a look at the functions that can access the contents of those records.

class CDBFile
 
...
private:
  void* GetFieldValue(Record* Rec, CField* Field);
  void SetFieldValue(Record* Rec, CField* Field, void* Value);
  BOOL IsBigger(void *v1, void *v2, CField* Criterium);
  BOOL IsSmaller(void *v1, void *v2, CField* Criterium);
...
 ;
 
 
  The first one is   GetFieldValue() . That function takes two 
arguments: a pointer to the record that is being accessed and a pointer
to the field descriptor (the field that contains the accessed value).
Knowing the offset and the length of the field within the contents string, 
the function first extracts the corresponding substring. Then it checks the
type of the field. If the field is of type   'N' (numeric value), 
there are two cases: if its decimal count is null, then the substring will 
be converted into a   long  integer value; if not, it will be 
converted into a   double  floating-point value. If the field is of
type   'L' (logical value), the substring will be converted into a 
boolean value (defined as   BOOL  in that package, and in 
Micro$oft's Visual C++). In other cases, if the field is of type 
  'C'  (character string) or   'D' (date), or even 
  'M' (Memo number for .DBT blocks) , there will be no 
conversion, the character substring will be kept `as is'. Maybe some 
specific conversions would be useful, particularly for dates or memo 
block numbers, but I did not need those functionalities for my own 
application. It's up to you to add more conversions, in respect of the GPL, 
of course. 
  In all cases, the result of the conversion will be put in a 
dynamically allocated pointer of the corresponding type, and that pointer 
will be returned as a   void  pointer. This is the inelegant aspect 
of the function: the programmer has to know exactly what kind of data he is 
receiving in that   void  pointer, and  he also has to delete that pointer 
(it has to be deleted, since it has been allocated dynamically). If 
he is using a fixed type of records (for a specific application, an address 
book for example) this will not be a problem. But if the type of records 
can vary in that application (a generic spreadsheet application, for 
example), the programmer will probably have to verify the type of the data, 
using public functions such as   GetFieldType() (see below).
  The same canvas applies to   SetFieldValue() , the other way round: 
when calling that function, a   void  pointer containing 
the value to be set is passed, along with a pointer to the field 
descriptor. The function then converts the contents of the   void  
pointer to the right substring, and copies it to the contents of the 
record. 
  The other two functions,   IsBigger()  and 
  IsSmaller() , use   Get Fi eld Va lue()  to compare two records
on the basis of their respective values for a given field. They are called by  
 SortAllRecords()  only so far.
  The public functions that can be used by the programmer are the 
following:
 [1]
 
  

class CDBFile
 
...
public:
  void SetFieldValue(char* Field, void* Value);
  void SetFieldValue(unsigned short FieldNum, void* Value);
  void* GetFieldValue(char* Field);
  void* GetFieldValue(unsigned short FieldNum);
  char GetFieldType(unsigned short NumField) 
       return (FirstField->GetField(NumField))->GetType();   
  void DeleteVoidPointer(void* Pointer, unsigned short Field);
  void DeleteVoidPointer(void* Pointer, char* Field);
...
 ;

 
 
  The overloaded and public versions of   SetFieldValue()  and 
  GetFieldValue()  are the equivalent of their private versions, 
but they use either the name or the number of the field to refer to it. 
  GetFieldType()  enables the programmer to know the type of the
field referenced by   NumField . I also chose to create  
 DeleteVoid Pointer()  so that the programmer can delete 
easily the   void  pointers he receives from calls to  
 GetFieldValue() . 
  That's all about handling the contents of the records, let's have
a look now at how the files are handled.

     3.4.3 Handling the files

  As I said earlier on, I did not implement the possibility to create 
a DBF file from scratch, adding fields in the field descriptor ring and the 
records or removing them. Therefore, one has to open an existing DBF file 
first, then one can only add, edit or remove records from that file, and
save it or save it as a new file (with another pathname). 
  When referring to Section  , the header of the file
contains a few specific parameters that describe the characteristics of the
file. They are implemented in CDBFile as private member variables:
  

class CDBFile
 
...
private:
  char PathName[256];           // Path name for the dBase III file 
  FILE *FileHandle;             // Handler for the dBase III file 
  unsigned short HeaderSize;    // Length of header structure 
  unsigned short FieldCount;    // Number of fields in each record 
  unsigned long RecordCount;    // Number of records in the file 
  BOOL ModifiedFlag;            // TRUE if the data has been modified 
  BOOL FullFileInMemory;        // TRUE if the entire file is loaded 
  unsigned short RecordLength;  // Length of the record strings 

  Record* RecordList;	// Head of the list of records 
  Record*	CurrentRec;	// Current record pointed in the list
  CField* FirstField;	// Head of the list of fields 
...
 ;
 
 
  Some of them can be accessed and modified directly by the programmer, 
using dedicated public functions; most of them, however, are only accessed
and processed internally by the member functions of the package, since the 
programmer should not need to read or modify them in any way. Here are the 
few functions that enable the programmer to do so:


class CDBFile
 
...
public:
  BOOL IsOpen()	
       return (BOOL)(FileHandle!=NULL);  
  unsigned long GetRecordCount()
       return RecordCount;  
  unsigned short GetFieldCount()	
       return FieldCount;  
...
 ;

 
  The other functions perform bigger tasks, of a higher level. Here they
are:
  

class CDBFile
 
...
public:
  CDBFile();
  CDBFile(char* Path);
   CDBFile();
  BOOL Clean();
  BOOL OpenFile(char* Path);
  BOOL CloseFile();
  unsigned long WriteAllToFile(char *Path=NULL);

private:
  BOOL WriteHeader(char* Path=NULL);
...
 ;
 
  The only private function here is used to rewrite the file header when
some of its information has changed. It is also used to write the modified 
file under a new pathname.
  The public function that uses   Write Header()  is  
 Write All To File() . That function is used only when the entire file has
been loaded into memory and has to be rewritten or saved under a new 
pathname. Note that it contains non-portable time-encoding functions, which
are specifically DOS-oriented, and will cause trouble when ported to 
UNIX / Linux. See the code in   "cdbfile.cpp"  for more details.
  The other public functions perform the following tasks:
  
    * CDBFile()  is the default constructor, whereas  
       CDB File(char* Path  creates the object and opens the file known as 
        Path ;
    * CDBFile()  is the default destructor;
    * Clean()  resets (or initializes) the contents of the  
       CDBFile  object, and is cal led both by the constructors and the
      destructor;
    * OpenFile(char* Path)  first resets the object and then opens
      a new file under   Path ; that function also sets most of the 
      data members to the values mentioned in the file, and particularly, 
      it builds the field descriptor ring.
    * CloseFile()  simply closes the file and resets all the data.
 
  That's all for the description of the code. Again, if you need more
details, RTFC ( Read The F***ing Codefiles! ).


5.  An example: the TestDBF file editor


  This is an elementary C-style console application, proposing a few 
tools to edit DBF files. It does not demonstrate   all  of the 
possibilities of   CDBFile , but it shows you most of them. Also,
note that not all the shortkeys are displayed on the top line of the 
console when you launch the program. This is a typically user-unfriendly
(but hopefully hacker/programmer-friendly) application.
  If you take a look at the source code ( 
 "testdbf.cpp" ), you will have a better idea of how the   CDBFile 
objects and its methods should be used within a program. The  
 "case 'e' :"  part of the   main()  function particularly deserves
your attention: it shows how to implement a generic record editor using
that package (which is non-trivial).
  I will not comment more on that application: the best thing for you
is definitely to have a look at the source code.      Hmmm...
Didn't I say that earlier on? I'm not sure...  :-)  


6.  Conclusion 

Well, that's all for the time being. I'm not quite sure that I will have time
enough to support that package in the next few months, but I will do my best. 
However, if you have some questions (in spite of all the efforts I did to 
make that project understandable :-), comments or bug reports, just e-mail
me at:   herve.gourmelon@enssat.fr  (until April 98). 
  As far as the portability is concerned, I only tried that package under
Micro oft's Visual C++. Porting it to Borland's or Watcom's should be no 
trouble, but beware of the definition of the 'BOOL type in 
'cdbfile.h': you might have to modify it using pre-compilation directives.
If you want ot use it under UNIX/Linux (using 'cc' or 'gcc'), you should be 
able to find a special GNU/Linux version that I released lately in the Linux 
part of the Sunsite archive (that version is easier to port, by the way), as follows: 
       ftp://sunsite.unc.edu/pub/Linux/devel/db/cdbfile.tar.gz
  If you decide to 
improve significantly the code and to add new functionalities, please contact
me: I will provide you with the     source of the postscript file you are
reading, so that you can add the description of your new functions or objects
and your name will be added to the contributor's file of the package, and to 
this page.

       Have fun! 
  

  Contributors 

  Herve GOURMELON  
  herve.gourmelon@enssat.fr  
  I hope that several people will add their names to that list...



 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -