📄 qimport3ascii.pas
字号:
unit QImport3ASCII;
{$I QImport3VerCtrl.Inc}
interface
uses
{$IFDEF QI_UNICODE}
{$IFDEF VCL10} WideStrings, {$ELSE} EmsWideStrings, {$ENDIF} GpTextFile,
{$ENDIF}
Windows, Classes, QImport3, SysUtils, IniFiles, EZDSLHsh, QImport3StrTypes;
type
TQImport3ASCII = class(TQImport3)
private
FComma: AnsiChar;
FQuote: AnsiChar;
FEncoding: TQICharsetType;
FCounter: Integer;
{$IFDEF QI_UNICODE}
FBuffStrW: WideString;
FFileW: TGpTextFile;
FColumnsW: TWideStrings;
{$ELSE}
FBuffStr: AnsiString;
FFile: TextFile;
FColumns: TStrings;
{$ENDIF}
FColumnsHash: THashTable;
FPosDataHash: THashTable;
function HasComma: Boolean;
procedure ReadColumns( const Str: qiString; AStrings: TqiStrings;
AColumnsHash: THashTable);
protected
function CheckProperties: Boolean; override;
procedure StartImport; override;
function CheckCondition: Boolean; override;
function Skip: Boolean; override;
procedure FillImportRow; override;
function ImportData: TQImportResult; override;
procedure ChangeCondition; override;
procedure FinishImport; override;
procedure DoLoadConfiguration(IniFile: TIniFile); override;
procedure DoSaveConfiguration(IniFile: TIniFile); override;
public
constructor Create(AOwner: TComponent); override;
published
property FileName;
property SkipFirstRows default 0;
(* property Comma: Char read FComma write FComma;
property Quote: Char read FQuote write FQuote;*)
property Comma: AnsiChar read FComma write FComma;
property Quote: AnsiChar read FQuote write FQuote;
property Encoding: TQICharsetType read FEncoding
write FEncoding default ctWinDefined;
end;
implementation
uses
QImport3StrIDs, DB, QImport3Common, EmsWideStrUtils, EzdslBse;
type
PPosData = ^TPosData;
TPosData = record
Pos: Integer;
Len: Integer;
end;
PStrData = ^TStrData;
TStrData = record
Str: qiString;
end;
procedure DisposePosHashData(AData: Pointer);
begin
Dispose(AData);
end;
procedure DisposeColumnsHashData(AData: Pointer);
begin
Finalize(PStrData(AData)^);
Dispose(AData);
end;
{ TQImport3ASCII }
constructor TQImport3ASCII.Create(AOwner: TComponent);
begin
inherited;
SkipFirstRows := 0;
FComma := AnsiChar(GetListSeparator);
FQuote := '"';
FEncoding := ctWinDefined;
end;
function TQImport3ASCII.CheckProperties: Boolean;
var
i, j: Integer;
begin
Result := inherited CheckProperties;
if HasComma then // example field=2
begin
for i := 0 to Map.Count - 1 do
try
StrToInt(Map.Values[Map.Names[i]]);
except
on E: EConvertError do
raise EQImportError.Create(QImportLoadStr(QIE_MapMissing));
end;
end
else begin // example: field=3;5
for i := 0 to Map.Count - 1 do
begin
j := Pos(';', Map.Values[Map.Names[i]]);
if j = 0 then
raise EQImportError.Create(QImportLoadStr(QIE_MapMissing))
else begin
try
StrToInt(Copy(Map.Values[Map.Names[i]], 1, j - 1));
except
on E:EConvertError do
raise EQImportError.Create(QImportLoadStr(QIE_MapMissing));
end;
try
StrToInt(Copy(Map.Values[Map.Names[i]], j + 1, Length(Map.Values[Map.Names[i]]) - j));
except
on E:EConvertError do
raise EQImportError.Create(QImportLoadStr(QIE_MapMissing));
end;
end;
end;
end
end;
procedure TQImport3ASCII.StartImport;
var
i, k: Integer;
pi: Pointer;
str: string;
posData: PPosData;
begin
{$IFDEF QI_UNICODE}
FFileW := TGpTextFile.CreateEx(FileName, FILE_ATTRIBUTE_NORMAL, GENERIC_READ, FILE_SHARE_READ);
FFileW.Reset;
FFileW.Codepage := ToCodepage(FEncoding);
FColumnsW := TWideStringList.Create;
{$ELSE}
AssignFile(FFile, FileName);
Reset(FFile);
FColumns := TStringList.Create;
{$ENDIF}
FColumnsHash := THashTable.Create(True);
FColumnsHash.TableSize := Map.Count;
FColumnsHash.DisposeData := DisposeColumnsHashData;
FPosDataHash := THashTable.Create(True);
FPosDataHash.TableSize := Map.Count;
FPosDataHash.DisposeData := DisposePosHashData;
for i := 0 to Map.Count - 1 do
begin
if FImportRow.MapNameIdxHash.Search(Map.Names[i], pi) then
begin
k := Integer(pi);
{$IFDEF VCL7}
str := Map.ValueFromIndex[k];
{$ELSE}
str := Map.Values[Map.Names[k]];
{$ENDIF}
New(posData);
posData^.Pos := StrToIntDef(Copy(str, 1, Pos(';', str) - 1), 0);
posData^.Len := StrToIntDef(Copy(str, Pos(';', str) + 1, Length(str)), 0);
FPosDataHash.Insert(Map.Names[i], posData);
end;
end;
FCounter := 0;
end;
function TQImport3ASCII.CheckCondition: Boolean;
begin
{$IFDEF QI_UNICODE}
Result := not FFileW.Eof;
{$ELSE}
Result := not Eof(FFile);
{$ENDIF}
end;
function TQImport3ASCII.Skip: Boolean;
function BuffEmpty: Boolean;
begin
{$IFDEF QI_UNICODE}
Result := Trim(FBuffStrW) = '';
{$ELSE}
Result := Trim(FBuffStr) = '';
{$ENDIF}
end;
begin
{$IFDEF QI_UNICODE}
FBuffStrW := FFileW.ReadLn;
if not HasComma then
ReplaceTabs(FBuffStrW);
{$ELSE}
Readln(FFile, FBuffStr);
if not HasComma then
ReplaceTabs(FBuffStr);
{$ENDIF}
Result := (SkipFirstRows > 0) and (FCounter < SkipFirstRows);
if Result then
Inc(FCounter);
Result := Result or BuffEmpty;
end;
procedure TQImport3ASCII.FillImportRow;
var
p: Pointer;
j, k: Integer;
ps: PStrData;
begin
FImportRow.ClearValues;
FColumnsHash.Empty();
{$IFDEF QI_UNICODE}
ReadColumns(FBuffStrW, FColumnsW, FColumnsHash);
{$ELSE}
ReadColumns(FBuffStr, FColumns, FColumnsHash);
{$ENDIF}
for j := 0 to FImportRow.Count - 1 do
begin
if FImportRow.MapNameIdxHash.Search(FImportRow[j].Name, p) then
begin
k := Integer(p);
{$IFDEF QI_UNICODE}
try
if HasComma then
{$IFDEF VCL7}
FBuffStrW := FColumnsW[StrToInt(Map.ValueFromIndex[k]) - 1]
{$ELSE}
FBuffStrW := FColumnsW[StrToInt(Map.Values[Map.Names[k]]) - 1]
{$ENDIF}
else begin
ps := FColumnsHash.Examine(FImportRow[j].Name);
if ps <> nil then
FBuffStrW := ps^.Str;
end;
except
FBuffStrW := '';
end;
FImportRow.SetValue(Map.Names[k], FBuffStrW, False);
{$ELSE}
try
if HasComma then
{$IFDEF VCL7}
FBuffStr := FColumns[StrToInt(Map.ValueFromIndex[k]) - 1]
{$ELSE}
FBuffStr := FColumns[StrToInt(Map.Values[Map.Names[k]]) - 1]
{$ENDIF}
else begin
ps := FColumnsHash.Examine(FImportRow[j].Name);
if ps <> nil then
FBuffStr := ps^.Str;
end;
except
FBuffStr := '';
end;
FImportRow.SetValue(Map.Names[k], FBuffStr, False);
{$ENDIF}
end;
DoUserDataFormat(FImportRow[j]);
end;
end;
function TQImport3ASCII.ImportData: TQImportResult;
begin
Result := qirOk;
try
try
if Canceled and not CanContinue then
begin
Result := qirBreak;
Exit;
end;
DataManipulation;
except
on E:Exception do
begin
try
DestinationCancel;
except
end;
DoImportError(E);
Result := qirContinue;
Exit;
end;
end;
finally
if (not IsCSV) and (CommitRecCount > 0) and not CommitAfterDone and
(
((ImportedRecs + ErrorRecs) > 0)
and ((ImportedRecs + ErrorRecs) mod CommitRecCount = 0)
)
then
DoNeedCommit;
if (ImportRecCount > 0) and
((ImportedRecs + ErrorRecs) mod ImportRecCount = 0) then
Result := qirBreak;
end;
end;
procedure TQImport3ASCII.ChangeCondition;
begin
end;
procedure TQImport3ASCII.FinishImport;
begin
try
if not Canceled and not IsCSV then
begin
if CommitAfterDone then
DoNeedCommit
else if (CommitRecCount > 0) and ((ImportedRecs + ErrorRecs) mod CommitRecCount > 0) then
DoNeedCommit;
end;
finally
{$IFDEF QI_UNICODE}
if Assigned(FColumnsW) then
FColumnsW.Free;
FFileW.Free;
{$ELSE}
if Assigned(FColumns) then
FColumns.Free;
CloseFile(FFile);
{$ENDIF}
FColumnsHash.Free;
FPosDataHash.Free;
end;
end;
procedure TQImport3ASCII.DoLoadConfiguration(IniFile: TIniFile);
begin
inherited;
with IniFile do
begin
SkipFirstRows := ReadInteger(ASCII_OPTIONS, ASCII_SKIP_LINES, SkipFirstRows);
Encoding := TQICharsetType(ReadInteger(ASCII_OPTIONS, ASCII_ENCODING, Integer(Encoding)));
Comma := Str2Char(ReadString(ASCII_OPTIONS, ASCII_COMMA,
Char2Str(Comma)), Comma);
Quote := Str2Char(ReadString(ASCII_OPTIONS, ASCII_QUOTE,
Char2Str( Quote)), Quote);
end;
end;
procedure TQImport3ASCII.DoSaveConfiguration(IniFile: TIniFile);
begin
inherited;
with IniFile do
begin
WriteInteger(ASCII_OPTIONS, ASCII_SKIP_LINES, SkipFirstRows);
WriteInteger(ASCII_OPTIONS, ASCII_ENCODING, Integer(Encoding));
WriteString(ASCII_OPTIONS, ASCII_COMMA, string(Comma));
WriteString(ASCII_OPTIONS, ASCII_QUOTE, string(Quote));
end;
end;
function TQImport3ASCII.HasComma: Boolean;
begin
Result := FComma <> #0;
end;
procedure TQImport3ASCII.ReadColumns(
const Str: qiString;
AStrings: TqiStrings;
AColumnsHash: THashTable);
var
P, L, i: Integer;
pi: Pointer;
ps: PStrData;
begin
if HasComma then
begin
CSVStringToStrings(Str, Quote, Comma, AStrings);
end
else begin
for i := 0 to Map.Count - 1 do
begin
if FPosDataHash.Search(Map.Names[i], pi) then
begin
P := PPosData(pi)^.Pos;
L := PPosData(pi)^.Len;
New(ps);
ps^.Str := Copy(Str, P + 1, L);
AColumnsHash.Insert(Map.Names[i], ps);
end;
end;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -