fpfixedexport.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. unit fpfixedexport;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, db, fpDBExport;
  6. { TFixedLengthExportFieldItem }
  7. Type
  8. TFixedLengthExportFieldItem = Class(TExportFieldItem)
  9. private
  10. FWidth: Integer;
  11. FAlignField: TAlignField;
  12. Public
  13. Procedure Assign(Source : TPersistent); override;
  14. Published
  15. Property Width : Integer Read FWidth Write FWidth;
  16. Property AlignField: TAlignField Read FAlignField write FAlignField;
  17. end;
  18. { TCustomFixedLengthExporter }
  19. TCharMode = (cmANSI,cmUTF8,cmUTF16);
  20. { TFixedExportFormatSettings }
  21. TFixedExportFormatSettings = Class (TExportFormatSettings)
  22. private
  23. FCharMode: TCharMode;
  24. FColumnSeparatorSpaceCount: Integer;
  25. FHeaderRow: Boolean;
  26. Public
  27. Procedure Assign(Source: TPersistent); override;
  28. Published
  29. // Whether or not the file should have a header row with field names
  30. Property HeaderRow : Boolean Read FHeaderRow Write FHeaderRow default true;
  31. // How to handle Unicode ?
  32. Property CharMode : TCharMode Read FCharMode Write FCharMode;
  33. // Number of separator spaces between columns. Default 0.
  34. Property ColumnSeparatorSpaceCount : Integer Read FColumnSeparatorSpaceCount Write FColumnSeparatorSpaceCount;
  35. end;
  36. TCustomFixedLengthExporter = Class(TCustomFileExporter)
  37. Private
  38. FCurrentRow : RawByteString;
  39. FCurrentRowUnicode : UnicodeString;
  40. FSpaces : RawByteString;
  41. FSpacesUnicode : UnicodeString;
  42. function GetCharMode: TCharMode;
  43. function GeTFixedExportFormatSettings: TFixedExportFormatSettings;
  44. procedure SetFixedExportFormatSettings(AValue: TFixedExportFormatSettings);
  45. Protected
  46. function ExportFieldAsUniCodeString(EF: TExportFieldItem; isHeader: Boolean=False): UnicodeString; virtual;
  47. procedure ExportFieldAnsi(EF: TExportFieldItem; isHeader: Boolean=False); virtual;
  48. procedure ExportFieldUTF16(EF: TExportFieldItem; isHeader: Boolean=False); virtual;
  49. procedure ExportFieldUTF8(EF: TExportFieldItem; isHeader: Boolean=False); virtual;
  50. Procedure BuildDefaultFieldMap(AMap : TExportFields); override;
  51. Function CreateExportFields : TExportFields; override;
  52. Function CreateFormatSettings: TCustomExportFormatSettings; override;
  53. Procedure DoBeforeExecute; override;
  54. Procedure DoAfterExecute; override;
  55. Procedure DoDataRowStart; override;
  56. Procedure ExportField(EF : TExportFieldItem); override;
  57. Procedure DoDataRowEnd; override;
  58. Procedure DoDataHeader; override;
  59. Property CharMode : TCharMode Read GetCharMode;
  60. Property FormatSettings : TFixedExportFormatSettings Read GetFixedExportFormatSettings Write SetFixedExportFormatSettings;
  61. end;
  62. TFixedLengthExporter = Class(TCustomFixedLengthExporter)
  63. Published
  64. Property FileName;
  65. Property Dataset;
  66. Property ExportFields;
  67. Property FromCurrent;
  68. Property RestorePosition;
  69. Property FormatSettings;
  70. Property OnExportRow;
  71. end;
  72. Procedure RegisterFixedExportFormat;
  73. Procedure UnRegisterFixedExportFormat;
  74. Const
  75. SFixedLengthExport = 'Fixed';
  76. SFixedLengthExtensions = '.txt';
  77. Resourcestring
  78. SFixedLengthDescription = 'Text file with fixed length records';
  79. implementation
  80. uses math;
  81. { TFixedExportFormatSettings }
  82. procedure TFixedExportFormatSettings.Assign(Source: TPersistent);
  83. begin
  84. if (Source is TFixedExportFormatSettings) then
  85. begin
  86. CharMode:=TFixedExportFormatSettings(Source).CharMode;
  87. HeaderRow:=TFixedExportFormatSettings(Source).HeaderRow;
  88. ColumnSeparatorSpaceCount:=TFixedExportFormatSettings(Source).ColumnSeparatorSpaceCount;
  89. end;
  90. inherited Assign(Source);
  91. end;
  92. { TFixedLengthExportFieldItem }
  93. procedure TFixedLengthExportFieldItem.Assign(Source: TPersistent);
  94. Var
  95. FL : TFixedLengthExportFieldItem;
  96. begin
  97. If Source is TFixedLengthExportFieldItem then
  98. begin
  99. FL:=Source as TFixedLengthExportFieldItem;
  100. Width:=FL.Width;
  101. AlignField:=FL.AlignFIeld;
  102. end;
  103. inherited Assign(Source);
  104. end;
  105. { TCustomFixedLengthExporter }
  106. procedure TCustomFixedLengthExporter.SetFixedExportFormatSettings(AValue: TFixedExportFormatSettings);
  107. begin
  108. Inherited FormatSettings:=AValue;
  109. end;
  110. function TCustomFixedLengthExporter.GetCharMode: TCharMode;
  111. begin
  112. Result:=FormatSettings.CharMode;
  113. end;
  114. function TCustomFixedLengthExporter.GeTFixedExportFormatSettings: TFixedExportFormatSettings;
  115. begin
  116. Result:=(Inherited Formatsettings) as TFixedExportFormatSettings;
  117. end;
  118. procedure TCustomFixedLengthExporter.BuildDefaultFieldMap(AMap: TExportFields);
  119. Const
  120. RightAlignedFields = IntFieldTypes+FloatFieldTypes;
  121. // Mapping to TFieldType
  122. FieldWidths : Array[TFieldType] of integer =
  123. (
  124. {ftUnknown} -1,
  125. {ftString} 0,
  126. {ftSmallint} 3,
  127. {ftInteger} 10,
  128. {ftWord} 5,
  129. {ftBoolean} 1,
  130. {ftFloat} 20,
  131. {ftCurrency} 20,
  132. {ftBCD} 20,
  133. {ftDate} 10,
  134. {ftTime} 8,
  135. {ftDateTime} 20,
  136. {ftBytes} 0,
  137. {ftVarBytes} 0,
  138. {ftAutoInc} 10,
  139. {ftBlob} 0,
  140. {ftMemo} 0,
  141. {ftGraphic} 0,
  142. {ftFmtMemo} 0,
  143. {ftParadoxOle} 0,
  144. {ftDBaseOle} 0,
  145. {ftTypedBinary} 0,
  146. {ftCursor} 0,
  147. {ftFixedChar} 0,
  148. {ftWideString} 0,
  149. {ftLargeint} 0,
  150. {ftADT} 0,
  151. {ftArray} 0,
  152. {ftReference} 0,
  153. {ftDataSet} 0,
  154. {ftOraBlob} 0,
  155. {ftOraClob} 0,
  156. {ftVariant} 0,
  157. {ftInterface} 0,
  158. {ftIDispatch} 0,
  159. {ftGuid} 0,
  160. {ftTimeStamp} 0,
  161. {ftFMTBcd} 0,
  162. {ftFixedWideChar} 0,
  163. {ftWideMemo} 0,
  164. {ftOraTimeStamp} 0,
  165. {ftOraInterval} 0,
  166. {ftLongWord} 10,
  167. {ftShortint} 4,
  168. {ftByte} 1,
  169. {ftExtended} 20
  170. );
  171. Function CalcLbool: integer;
  172. var
  173. LTrue,LFalse : Integer;
  174. begin
  175. Case charmode of
  176. cmUTF8:
  177. begin
  178. LTrue:=Length(UTF8Decode(FormatSettings.BooleanTrue));
  179. LFalse:=Length(UTF8Decode(FormatSettings.BooleanFalse));
  180. end;
  181. else
  182. LTrue:=Length(FormatSettings.BooleanTrue);
  183. LFalse:=Length(FormatSettings.BooleanFalse);
  184. end;
  185. Result:=Max(LTrue,LFalse);
  186. end;
  187. Var
  188. I,W,LBool : Integer;
  189. F : TField;
  190. FL : TFixedLengthExportFieldItem;
  191. begin
  192. inherited BuildDefaultFieldMap(AMap);
  193. lbool:=0;
  194. For I:=0 to AMap.Count-1 do
  195. begin
  196. FL:=TFixedLengthExportFieldItem(AMAP[i]);
  197. F:=Dataset.Fields[i];
  198. W:= FieldWidths[F.DataType];
  199. if F.DataType = ftBoolean then
  200. begin
  201. if lBool=0 then
  202. LBool:=CalcLBool;
  203. W:=lBool;
  204. end;
  205. If (W>0) then
  206. FL.Width:=W
  207. else if (W=0) then
  208. begin
  209. if (F.DataType in StringFieldTypes) then
  210. FL.Width:=F.Size;
  211. end;
  212. If (F.DataType in RightAlignedFields) then
  213. Fl.AlignField:=afRight;
  214. end;
  215. end;
  216. function TCustomFixedLengthExporter.CreateExportFields: TExportFields;
  217. begin
  218. Result:=TExportFields.Create(TFixedLengthExportFieldItem);
  219. end;
  220. function TCustomFixedLengthExporter.CreateFormatSettings: TCustomExportFormatSettings;
  221. begin
  222. Result:=TFixedExportFormatSettings.Create(True);
  223. end;
  224. procedure TCustomFixedLengthExporter.DoBeforeExecute;
  225. begin
  226. inherited DoBeforeExecute;
  227. OpenTextFile;
  228. FSpaces:=StringOfChar(' ',FormatSettings.ColumnSeparatorSpaceCount);
  229. FSpacesUnicode:=StringOfChar(' ',FormatSettings.ColumnSeparatorSpaceCount);
  230. end;
  231. procedure TCustomFixedLengthExporter.DoAfterExecute;
  232. begin
  233. CloseTextFile;
  234. inherited DoAfterExecute;
  235. end;
  236. procedure TCustomFixedLengthExporter.DoDataRowStart;
  237. begin
  238. FCurrentRow:='';
  239. end;
  240. procedure TCustomFixedLengthExporter.ExportField(EF: TExportFieldItem);
  241. begin
  242. Case CharMode of
  243. cmANSI : ExportFieldAnsi(EF);
  244. cmUTF8 : ExportFieldUTF8(EF);
  245. cmUTF16 : ExportFieldUTF16(EF);
  246. end;
  247. end;
  248. Function TCustomFixedLengthExporter.ExportFieldAsUniCodeString(EF: TExportFieldItem; isHeader : Boolean = False) : UnicodeString;
  249. Var
  250. S,SS : UnicodeString;
  251. FL : TFixedLengthExportFieldItem;
  252. L,W : Integer;
  253. begin
  254. if isHeader then
  255. S:=UTF8Decode(EF.ExportedName)
  256. else
  257. S:=UTF8Decode(FormatField(EF.Field));
  258. If EF is TFixedLengthExportFieldItem then
  259. begin
  260. FL:=TFixedLengthExportFieldItem(EF);
  261. W:=FL.Width;
  262. end
  263. else
  264. W:=Length(S);
  265. L:=Length(S);
  266. If L>W then
  267. begin
  268. If (FL.AlignField=afLeft) then
  269. S:=Copy(S,1,W)
  270. else
  271. Delete(S,1,L-W);
  272. end
  273. else if (L<W) then
  274. begin
  275. SS:=StringOfChar(' ',W-L);
  276. If FL.AlignField=afRight then
  277. S:=SS+S
  278. else
  279. S:=S+SS;
  280. end;
  281. Result:=S;
  282. end;
  283. procedure TCustomFixedLengthExporter.ExportFieldUTF16(EF: TExportFieldItem; isHeader : Boolean = False);
  284. begin
  285. if (FormatSettings.ColumnSeparatorSpaceCount>0) and (Length(FCurrentRowUnicode)>0) then
  286. FCurrentRowUnicode:=FCurrentRowUnicode+FSpacesUnicode;
  287. FCurrentRowUnicode:=FCurrentRowUnicode+ExportFieldAsUnicodeString(EF,isHeader);
  288. end;
  289. procedure TCustomFixedLengthExporter.ExportFieldUTF8(EF: TExportFieldItem; isHeader : Boolean = False);
  290. begin
  291. if (FormatSettings.ColumnSeparatorSpaceCount>0) and (Length(FCurrentRow)>0) then
  292. FCurrentRow:=FCurrentRow+FSpaces;
  293. FCurrentRow:=FCurrentRow+UTF8Encode(ExportFieldAsUnicodeString(EF,isHeader));
  294. end;
  295. procedure TCustomFixedLengthExporter.ExportFieldAnsi(EF: TExportFieldItem; isHeader : Boolean = False);
  296. Var
  297. S,SS : String;
  298. W,L : Integer;
  299. FL : TFixedLengthExportFieldItem;
  300. begin
  301. if isHeader then
  302. S:=EF.ExportedName
  303. else
  304. S:=FormatField(EF.Field);
  305. If EF is TFixedLengthExportFieldItem then
  306. begin
  307. FL:=TFixedLengthExportFieldItem(EF);
  308. W:=FL.Width;
  309. end
  310. else
  311. W:=Length(S);
  312. L:=Length(S);
  313. If L>W then
  314. begin
  315. If (FL.AlignField=afLeft) then
  316. S:=Copy(S,1,W)
  317. else
  318. Delete(S,1,L-W);
  319. end
  320. else if (L<W) then
  321. begin
  322. SS:=StringOfChar(' ',W-L);
  323. If FL.AlignField=afRight then
  324. S:=SS+S
  325. else
  326. S:=S+SS;
  327. end;
  328. if (FormatSettings.ColumnSeparatorSpaceCount>0) and (Length(FCurrentRow)>0) then
  329. FCurrentRow:=FCurrentRow+FSpaces;
  330. FCurrentRow:=FCurrentRow+S;
  331. end;
  332. procedure TCustomFixedLengthExporter.DoDataRowEnd;
  333. begin
  334. if (CharMode<>cmUTF16) then
  335. Writeln(TextFile,FCurrentRow)
  336. else
  337. Writeln(TextFile,FCurrentRowUnicode);
  338. FCurrentRow:='';
  339. FCurrentRowUnicode:='';
  340. end;
  341. procedure TCustomFixedLengthExporter.DoDataHeader;
  342. Var
  343. I : Integer;
  344. EF: TExportFieldItem;
  345. begin
  346. FCurrentRow:='';
  347. if FormatSettings.HeaderRow then
  348. begin
  349. For I:=0 to ExportFields.Count-1 do
  350. begin
  351. EF:=ExportFields[I];
  352. If EF.Enabled then
  353. Case CharMode of
  354. cmANSI : ExportFieldAnsi(EF,True);
  355. cmUTF8 : ExportFieldUTF8(EF,True);
  356. cmUTF16 : ExportFieldUTF16(EF,True);
  357. end;
  358. end;
  359. DoDataRowEnd;
  360. end;
  361. inherited DoDataHeader;
  362. end;
  363. Procedure RegisterFixedExportFormat;
  364. begin
  365. ExportFormats.RegisterExportFormat(SFixedLengthExport,SFixedLengthDescription,SFixedLengthExtensions,TFixedLengthExporter);
  366. end;
  367. Procedure UnRegisterFixedExportFormat;
  368. begin
  369. Exportformats.UnregisterExportFormat(SFixedLengthExport);
  370. end;
  371. end.