unit FileFunctions; interface uses Windows, Messages, SysUtils, Classes, Db, DbTables; function GetFileSize(const FileName: string): LongInt; procedure GetFileList(const sPath, sMask: string; var slFileList: TStringList); // { function Import( const FName: String; const nFieldCheck: Integer; const sFieldValueList: String; const InPartOfField: Boolean; DST: TTable; D: TDataBase ): Boolean; // } implementation uses Progress; { GetFileSize function } { Returns the size of the named file without opening the file. If the file doesn't exist, returns -1. } function GetFileSize(const FileName: string): LongInt; var SearchRec: TSearchRec; begin if FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec) = 0 then Result := SearchRec.Size else Result := -1; FindClose(SearchRec); // Releases memory allocated by FindFirst. end; // GetFileSize. procedure GetFileList(const sPath, sMask: string; var slFileList: TStringList); var FileInfo: TSearchRec; sFileSpec: string; begin sFileSpec := sPath + sMask; if (FindFirst(sFileSpec, faAnyFile, FileInfo) = 0) then begin repeat slfileList.Add(FileInfo.Name); until FindNext(FileInfo) <> 0; end; FindClose(FileInfo); end; // GetFileList. { Import function } { Reads a delimited string from FName and saves each line into a single table record in DST. Database D is required for transaction processing. Note: FName to have already been tested for existence prior to calling this procedure. } function Import( const FName: String; const nFieldCheck: Integer; const sFieldValueList: String; const InPartOfField: Boolean; DST: TTable; D: TDataBase ): Boolean; const RECORD_BYTES_C: Integer = 150; // Typical minimum bytes per record. PROGRESS_COUNTER_C: Integer=100; // Update Progress every 100 records read PROGRESS_MAX_C: Integer = 100; // Maximum progress is 100%. var nFileSize: Integer; // Actual file size. InputTextFile: TextFile; InputTextFileBuffer: array[1..4096] of Char; // 4KB buffer. sCaption : String; // Used for modifying Progress caption. ReadString: string; // Read in from the text file. ConvertString: TStringList; // Used to convert SDF format to strings. nFieldNumber : Integer; // Loop counter for saving field data. nFieldsRead : integer; // Number of field data items read. nProgressCounted : integer; // Count each set of PROGRESS_COUNTER_C. nFieldCount : Integer; // Number of fields in the table. Progress: TProgressForm; nCount: Integer; nSoFar: Integer; nFactor: Real; lCheckFieldValues: Boolean; lSaveToTable: Boolean; lResultCode: Boolean; lPartOfField: Boolean; begin // Use a local variable for speed - avoid reading the stack too often. lPartOfField := InpartOfField; nFileSize := GetFileSize(FName); if (nFileSize > 0) then begin // Assume 150 Bytes min. per record. nFactor := 100.0 * RECORD_BYTES_C / nFileSize; end else begin nFactor := 100.0; end; nCount := 0; // Number of fields in the table. nFieldCount := DST.FieldCount - 1; lResultCode := False; // Open the input (text) billing file for reading. AssignFile( InputTextFile, Fname ); // Bigger buffer for faster reads. System.SetTextBuf(InputTextFile, InputTextFileBuffer); Reset( InputTextFile ); Progress := TProgressForm.Create(NIL); Progress.Caption := 'Reading The Input Text File'; Progress.btnCancel.Visible := False; // Convert nFileSize to x100kBytes (based on 1.0MB=1,048,576B). nFileSize := nFileSize div 104858; Str( (nFileSize / 10.0):5:1, sCaption ); Progress.Msg.Caption := 'Reading ('+Trim(sCaption)+'MB) ...'; Progress.Show; Progress.ProcessWinMessages(Nil); ConvertString := TStringList.Create; // Used to convert SDF format to strings. try // Assume that the results table has already been emptied. // Process the whole of the input file. lCheckFieldValues := sFieldValueList <> ''; lSaveToTable := True; // Get the first occurence of the search string. Readln( InputTextFile, ReadString ); // To be sure the file isn't empty too... if (Length( ReadString ) > 0) or (not Eof( InputTextFile )) then begin nProgressCounted := 0; D.StartTransaction; // Continue to search through the remaining text of the file // for occurrences of the search string. On each each find, // process the resultant string. try repeat begin ConvertString.CommaText := ReadString; // Decode the line read. nFieldsRead := ConvertString.Count - 1; if lCheckFieldValues then begin lSaveToTable := (nFieldCheck < ConvertString.Count) and ((not lPartOfField and (Pos(Trim(ConvertString.Strings[nFieldCheck]),sFieldValueList)>0)) or (lPartOfField and (Pos(sFieldValueList,Trim(ConvertString.Strings[nFieldCheck]))>0))); end; if lSaveToTable then // Save the strings into the table. begin if (nFieldsRead > nFieldCount) then // Ignore excess information we do not have fields for in the table. begin nFieldsRead := nFieldCount; end; DST.Append; for nFieldNumber := 0 to nFieldsRead do begin DST.Fields[ nFieldNumber ].Value := ConvertString.Strings[ nFieldNumber ]; end; // for nFieldNumber := 0 to nFieldsRead do. end; // if lSaveToTable then. // Keep track of how much work has been done to date. Inc(nCount); Inc(nProgressCounted); if (nProgressCounted > PROGRESS_COUNTER_C) then // Report progress to the user. begin nSoFar := Round(nCount * nFactor); // Do not know how big the file is - make sure don't exceed 100%. if (nSoFar > PROGRESS_MAX_C) then begin Progress.ProgressBar1.Position := PROGRESS_MAX_C; end else begin Progress.ProgressBar1.Position := nSoFar; end; nProgressCounted := 0; end; // Let windows update all messages. Progress.ProcessWinMessages(Nil); // Read in the next line of data. Readln( InputTextFile, ReadString ); end; until Eof( InputTextFile ); lResultCode := True; except lResultCode := False; D.Rollback; // On failure, undo the changes - not useful anyway. raise; // Raise the exception to avoid call to CommitUpdates. end; // Now need to process the last line if CR-LF not at end. // BUT - nothing done ! D.Commit; end; finally // Done with the input file and resources, close them. CloseFile( InputTextFile ); Progress.Close; ConvertString.Free; end; Result := lResultCode; end; // function Import(). end.