Quick.Files.pas 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. { ***************************************************************************
  2. Copyright (c) 2016-2019 Kike Pérez
  3. Unit : Quick.Files
  4. Description : Files functions
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 09/03/2018
  8. Modified : 21/01/2019
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Files;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. {$IFDEF MSWINDOWS}
  28. Windows,
  29. {$ENDIF}
  30. {$IFDEF FPC}
  31. strutils,
  32. {$IFDEF LINUX}
  33. baseunix,
  34. {$ENDIF}
  35. {$ENDIF}
  36. DateUtils;
  37. {$IFDEF FPC}
  38. resourcestring
  39. SPathTooLong = 'The specified path is too long';
  40. SPathNotFound = 'The specified path was not found';
  41. SPathFormatNotSupported = 'The path format is not supported';
  42. SDirectoryNotEmpty = 'The specified directory is not empty';
  43. SDirectoryAlreadyExists = 'The specified directory already exists';
  44. SDirectoryInvalid = 'The specified directory name is invalid';
  45. SSourceDirIsDestDir = 'The source directory is the same as the destination directory';
  46. SSourceFileIsDestFile = 'The source file is the same as the destination file';
  47. SPathToFileNeeded = 'The path must specify a file';
  48. SSameRootDrive = 'The source and destination paths must contain the same root drive';
  49. SDriveNotFound = 'The drive cannot be found';
  50. SFileNotFound = 'The specified file was not found';
  51. SFileAlreadyExists = 'The specified file already exists';
  52. SInvalidCharsInPath = 'Invalid characters in path';
  53. SInvalidCharsInFileName = 'Invalid characters in file name';
  54. {$ENDIF}
  55. type
  56. {$IFNDEF FPC}
  57. TTextFileOperation = (tfOpenRead,tfOpenOverwrite,tfOpenAppend);
  58. TTextStreamFile = class
  59. private
  60. fReadStream : TStreamReader;
  61. fWriteStream : TStreamWriter;
  62. function GetEOF : Boolean;
  63. public
  64. constructor Create(const aFileName : string; aOpenMode : TTextFileOperation);
  65. destructor Destroy; override;
  66. function ReadLn: string; overload;
  67. function ReadLn(out Data: string): Boolean; overload;
  68. procedure WriteLn (const Data : string);
  69. procedure Close;
  70. property EOF: Boolean read GetEOF;
  71. end;
  72. {$IF Defined(MACOS) OR Defined(NEXTGEN)}
  73. TFileTime = LongInt;
  74. {$ENDIF}
  75. {$ELSE}
  76. {$IFDEF LINUX}
  77. TFILETIME = LongInt;
  78. {$ENDIF}
  79. {$ENDIF}
  80. {$IFDEF FPC}
  81. EStreamError = class(Exception);
  82. EFileStreamError = class(EStreamError)
  83. constructor Create(ResStringRec: PResStringRec; const FileName: string);
  84. end;
  85. TPathPrefixType = (pptNoPrefix, pptExtended, pptExtendedUNC);
  86. TPath = class
  87. private
  88. const
  89. FCCurrentDir: string = '.';
  90. FCParentDir: string = '..';
  91. FCExtendedPrefix: string = '\\?\';
  92. FCExtendedUNCPrefix: string = '\\?\UNC\';
  93. class procedure CheckPathLength(const Path: string; const MaxLength: Integer);
  94. public
  95. class function GetFileNameWithoutExtension(const FileName : string) : string;
  96. class function GetDirectoryName(const FileName : string) : string;
  97. class function GetExtension(const Path : string) : string;
  98. class function ChangeExtension(const Path, NewExtension : string) : string;
  99. end;
  100. TDirectory = class
  101. public
  102. class function Exists(const Path: string; FollowLink: Boolean = True): Boolean;
  103. end;
  104. TFile = class
  105. public
  106. class function Exists(const Path : string) : Boolean;
  107. class function IsInUse(const Path : string) : Boolean;
  108. class function GetSize(const Path : string) : Int64;
  109. class function Create(const Path: string; const BufferSize: Integer): TFileStream; overload;
  110. class function Create(const Path: string): TFileStream; overload;
  111. class function GetExtension(const Path : string) : string;
  112. class function GetCreationTime(const Path : string): TDateTime;
  113. class function GetLastAccessTime(const Path : string): TDateTime;
  114. class function GetLastWriteTime(const Path : string): TDateTime;
  115. class procedure SetCreationTime(const Path: string; const CreationTime: TDateTime);
  116. class procedure SetLastAccessTime(const Path: string; const LastAccessTime: TDateTime);
  117. class procedure SetLastWriteTime(const Path: string; const LastWriteTime: TDateTime);
  118. class function IsReadOnly(const Path : string) : Boolean;
  119. class function Delete(const Path : string) : Boolean;
  120. class function Move(const SourceFileName, DestFileName: string) : Boolean;
  121. end;
  122. TTextWriter = class
  123. public
  124. procedure Close; virtual; abstract;
  125. procedure Flush; virtual; abstract;
  126. procedure Write(Value: Boolean); overload; virtual; abstract;
  127. procedure Write(Value: Char); overload; virtual; abstract;
  128. procedure Write(Value: Double); overload; virtual; abstract;
  129. procedure Write(Value: Integer); overload; virtual; abstract;
  130. procedure Write(Value: Int64); overload; virtual; abstract;
  131. procedure Write(Value: TObject); overload; virtual; abstract;
  132. procedure Write(Value: Single); overload; virtual; abstract;
  133. procedure Write(const Value: string); overload; virtual; abstract;
  134. procedure Write(const aFormat: string; Args: array of const); overload; virtual; abstract;
  135. procedure WriteLine; overload; virtual; abstract;
  136. procedure WriteLine(Value: Boolean); overload; virtual; abstract;
  137. procedure WriteLine(Value: Char); overload; virtual; abstract;
  138. procedure WriteLine(Value: Double); overload; virtual; abstract;
  139. procedure WriteLine(Value: Integer); overload; virtual; abstract;
  140. procedure WriteLine(Value: Int64); overload; virtual; abstract;
  141. procedure WriteLine(Value: TObject); overload; virtual; abstract;
  142. procedure WriteLine(Value: Single); overload; virtual; abstract;
  143. procedure WriteLine(const Value: string); overload; virtual; abstract;
  144. procedure WriteLine(const aFormat: string; Args: array of const); overload; virtual; abstract;
  145. end;
  146. TStreamWriter = class(TTextWriter)
  147. private
  148. FStream: TStream;
  149. FEncoding: TEncoding;
  150. FNewLine: string;
  151. FAutoFlush: Boolean;
  152. FOwnsStream: Boolean;
  153. FBufferIndex: Integer;
  154. FBuffer: TBytes;
  155. procedure WriteBytes(Bytes: TBytes);
  156. public
  157. constructor Create(Stream: TStream); overload;
  158. constructor Create(Stream: TStream; Encoding: TEncoding; BufferSize: Integer = 4096); overload;
  159. constructor Create(const Filename: string; Append: Boolean = False); overload;
  160. constructor Create(const Filename: string; Append: Boolean; Encoding: TEncoding; BufferSize: Integer = 4096); overload;
  161. destructor Destroy; override;
  162. procedure Close; override;
  163. procedure Flush; override;
  164. procedure OwnStream; inline;
  165. procedure Write(Value: Boolean); override;
  166. procedure Write(Value: Char); override;
  167. procedure Write(Value: Double); override;
  168. procedure Write(Value: Integer); override;
  169. procedure Write(Value: Int64); override;
  170. procedure Write(Value: TObject); override;
  171. procedure Write(Value: Single); override;
  172. procedure Write(const Value: string); override;
  173. procedure Write(const aFormat: string; Args: array of const); override;
  174. procedure WriteLine; override;
  175. procedure WriteLine(Value: Boolean); override;
  176. procedure WriteLine(Value: Char); override;
  177. procedure WriteLine(Value: Double); override;
  178. procedure WriteLine(Value: Integer); override;
  179. procedure WriteLine(Value: Int64); override;
  180. procedure WriteLine(Value: TObject); override;
  181. procedure WriteLine(Value: Single); override;
  182. procedure WriteLine(const Value: string); override;
  183. procedure WriteLine(const aFormat: string; Args: array of const); override;
  184. property AutoFlush: Boolean read FAutoFlush write FAutoFlush;
  185. property NewLine: string read FNewLine write FNewLine;
  186. property Encoding: TEncoding read FEncoding;
  187. property BaseStream: TStream read FStream;
  188. end;
  189. {$ENDIF FPC}
  190. function CreateDummyFile(const aFilename : string; const aSize : Int64) : Boolean;
  191. procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
  192. procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string); overload;
  193. procedure MergeFiles(aFilenames : array of string; const aOutFileName : string); overload;
  194. {$IFNDEF NEXTGEN}
  195. function IsFileInUse(const aFileName : string) : Boolean;
  196. {$ENDIF}
  197. procedure FileReplaceText(const aFileName, aSearchText, AReplaceText : string);
  198. function FileSearchText(const aFileName, SearchText: string; caseSensitive : Boolean): Longint;
  199. function GetCreationTime(const aFilename : string): TDateTime;
  200. function GetLastAccessTime(const aFileName: string): TDateTime;
  201. function GetLastWriteTime(const aFileName : string): TDateTime;
  202. {$IFDEF FPC}
  203. function FindDelimiter(const Delimiters, S: string; StartIdx: Integer = 1): Integer;
  204. {$ENDIF}
  205. function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
  206. procedure SetDateTimeInfo(const Path: string; const CreationTime, LastAccessTime, LastWriteTime: PDateTime; const UseLocalTimeZone: Boolean);
  207. implementation
  208. { TTextStreamFile }
  209. {$IFNDEF FPC}
  210. constructor TTextStreamFile.Create(const aFileName : string; aOpenMode : TTextFileOperation);
  211. var
  212. Append : Boolean;
  213. begin
  214. if aOpenMode = tfOpenRead then fReadStream := TStreamReader.Create(aFileName,True)
  215. else
  216. begin
  217. if aOpenMode = tfOpenAppend then Append := True
  218. else Append := False;
  219. fWriteStream := TStreamWriter.Create(aFileName,Append);
  220. end;
  221. end;
  222. destructor TTextStreamFile.Destroy;
  223. begin
  224. if Assigned(fReadStream) then fReadStream.Free;
  225. if Assigned(fWriteStream) then fWriteStream.Free;
  226. inherited Destroy;
  227. end;
  228. function TTextStreamFile.ReadLn(out Data: string): Boolean;
  229. begin
  230. Data := fReadStream.ReadLine;
  231. Result := Data <> '';
  232. end;
  233. function TTextStreamFile.ReadLn: string;
  234. begin
  235. Result := fReadStream.ReadLine;
  236. end;
  237. procedure TTextStreamFile.WriteLn (const Data : string);
  238. begin
  239. fWriteStream.WriteLine(Data);
  240. end;
  241. function TTextStreamFile.GetEOF : Boolean;
  242. begin
  243. Result := fReadStream.EndOfStream;
  244. end;
  245. procedure TTextStreamFile.Close;
  246. begin
  247. if Assigned(fReadStream) then fReadStream.Close;
  248. if Assigned(fWriteStream) then fWriteStream.Close;
  249. end;
  250. {$ENDIF NFPC}
  251. {$IFDEF FPC}
  252. { EFileStreamError }
  253. constructor EFileStreamError.Create(ResStringRec: PResStringRec;
  254. const FileName: string);
  255. begin
  256. {$IFNDEF LINUX}
  257. inherited CreateResFmt(ResStringRec, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
  258. {$ELSE}
  259. inherited CreateResFmt(ResStringRec, [ExpandFileName(FileName), SysErrorMessage(errno)]);
  260. {$ENDIF}
  261. end;
  262. { TPath }
  263. class function TPath.GetFileNameWithoutExtension(const FileName: String): String;
  264. var
  265. fname : string;
  266. begin
  267. fname := ExtractFileName(FileName);
  268. Result := Copy(fname, 1, Length(fname) - Length(ExtractFileExt(fname)));
  269. end;
  270. class function TPath.ChangeExtension(const Path, NewExtension : string) : string;
  271. var
  272. dot : string;
  273. begin
  274. if NewExtension.Contains('.') then dot := ''
  275. else dot := '.';
  276. Result := TPath.GetFileNameWithoutExtension(Path) + dot + NewExtension;
  277. end;
  278. class function TPath.GetDirectoryName(const FileName : string) : string;
  279. begin
  280. Result := ExtractFileDir(Filename);
  281. end;
  282. class procedure TPath.CheckPathLength(const Path: string; const MaxLength: Integer);
  283. begin
  284. {$IFDEF MSWINDOWS}
  285. if (Length(Path) >= MaxLength) then
  286. {$ENDIF MSWINDOWS}
  287. {$IFDEF POSIX}
  288. if (Length(UTF8Encode(Path)) >= MaxLength) then
  289. {$ENDIF POSIX}
  290. raise EPathTooLongException.CreateRes(@SPathTooLong);
  291. end;
  292. class function TPath.GetExtension(const Path : string) : string;
  293. begin
  294. Result := ExtractFileExt(Path);
  295. end;
  296. { TDirectory }
  297. class function TDirectory.Exists(const Path: string; FollowLink: Boolean = True): Boolean;
  298. begin
  299. Result := DirectoryExists(Path);
  300. end;
  301. { TFile }
  302. class function TFile.Exists(const Path : string) : Boolean;
  303. begin
  304. Result := FileExists(Path);
  305. end;
  306. class procedure TFile.SetCreationTime(const Path: string; const CreationTime: TDateTime);
  307. begin
  308. SetDateTimeInfo(Path,@CreationTime,nil,nil,True);
  309. end;
  310. class procedure TFile.SetLastAccessTime(const Path: string; const LastAccessTime: TDateTime);
  311. begin
  312. SetDateTimeInfo(Path,nil,@LastAccessTime,nil,True);
  313. end;
  314. class procedure TFile.SetLastWriteTime(const Path: string; const LastWriteTime: TDateTime);
  315. begin
  316. SetDateTimeInfo(Path,nil,nil,@LastWriteTime,True);
  317. end;
  318. class function TFile.IsReadOnly(const Path : string) : Boolean;
  319. begin
  320. Result := FileIsReadOnly(Path);
  321. end;
  322. class function TFile.Delete(const Path : string) : Boolean;
  323. begin
  324. Result := DeleteFile(PChar(Path));
  325. end;
  326. class function TFile.Move(const SourceFileName, DestFileName: string) : Boolean;
  327. begin
  328. {$IFNDEF LINUX}
  329. Result := MoveFile(PChar(SourceFileName),PChar(DestFileName));
  330. {$ELSE}
  331. Result := RenameFile(PChar(SourceFileName),PChar(DestFileName));
  332. {$ENDIF}
  333. end;
  334. {$IFNDEF NEXTGEN}
  335. class function TFile.IsInUse(const Path : string) : Boolean;
  336. begin
  337. Result := IsFileInUse(Path);
  338. end;
  339. {$ENDIF}
  340. class function TFile.GetSize(const Path : string) : Int64;
  341. var
  342. f : File of Byte;
  343. begin
  344. Assign(f,Path);
  345. try
  346. Reset (f);
  347. Result := FileSize(f);
  348. finally
  349. CloseFile(f);
  350. end;
  351. end;
  352. class function TFile.GetExtension(const Path : string) : string;
  353. begin
  354. Result := ExtractFileExt(Path);
  355. end;
  356. class function TFile.GetCreationTime(const Path : string) : TDateTime;
  357. begin
  358. Result := Quick.Files.GetCreationTime(Path);
  359. end;
  360. class function TFile.GetLastAccessTime(const Path : string) : TDateTime;
  361. begin
  362. Result := Quick.Files.GetLastAccessTime(Path);
  363. end;
  364. class function TFile.GetLastWriteTime(const Path : string) : TDateTime;
  365. begin
  366. Result := Quick.Files.GetLastWriteTime(Path);
  367. end;
  368. class function TFile.Create(const Path: string; const BufferSize: Integer): TFileStream;
  369. begin
  370. try
  371. Result := TFileStream.Create(Path,fmCreate);
  372. except
  373. on E: EFileStreamError do
  374. raise EInOutError.Create(E.Message);
  375. end;
  376. end;
  377. class function TFile.Create(const Path: string): TFileStream;
  378. begin
  379. Result := Create(Path, 0);
  380. end;
  381. { TStreamWriter }
  382. procedure TStreamWriter.Close;
  383. begin
  384. Flush;
  385. if FOwnsStream then
  386. FreeAndNil(FStream);
  387. end;
  388. constructor TStreamWriter.Create(Stream: TStream);
  389. begin
  390. inherited Create;
  391. FOwnsStream := False;
  392. FStream := Stream;
  393. FEncoding := TEncoding.UTF8;
  394. SetLength(FBuffer, 1024);
  395. FBufferIndex := 0;
  396. FNewLine := sLineBreak;
  397. FAutoFlush := True;
  398. end;
  399. constructor TStreamWriter.Create(Stream: TStream; Encoding: TEncoding; BufferSize: Integer);
  400. begin
  401. inherited Create;
  402. FOwnsStream := False;
  403. FStream := Stream;
  404. FEncoding := Encoding;
  405. if BufferSize >= 128 then
  406. SetLength(FBuffer, BufferSize)
  407. else
  408. SetLength(FBuffer, 128);
  409. FBufferIndex := 0;
  410. FNewLine := sLineBreak;
  411. FAutoFlush := True;
  412. if Stream.Position = 0 then
  413. WriteBytes(FEncoding.GetPreamble);
  414. end;
  415. constructor TStreamWriter.Create(const Filename: string; Append: Boolean);
  416. begin
  417. if (not FileExists(Filename)) or (not Append) then
  418. FStream := TFileStream.Create(Filename, fmCreate)
  419. else
  420. begin
  421. FStream := TFileStream.Create(Filename, fmOpenWrite);
  422. FStream.Seek(0, soEnd);
  423. end;
  424. Create(FStream);
  425. FOwnsStream := True;
  426. end;
  427. constructor TStreamWriter.Create(const Filename: string; Append: Boolean;
  428. Encoding: TEncoding; BufferSize: Integer);
  429. begin
  430. if (not FileExists(Filename)) or (not Append) then
  431. FStream := TFileStream.Create(Filename, fmCreate)
  432. else
  433. begin
  434. FStream := TFileStream.Create(Filename, fmOpenWrite);
  435. FStream.Seek(0, soEnd);
  436. end;
  437. Create(FStream, Encoding, BufferSize);
  438. FOwnsStream := True;
  439. end;
  440. destructor TStreamWriter.Destroy;
  441. begin
  442. Close;
  443. SetLength(FBuffer, 0);
  444. inherited;
  445. end;
  446. procedure TStreamWriter.Flush;
  447. begin
  448. if FBufferIndex = 0 then
  449. Exit;
  450. if FStream = nil then
  451. Exit;
  452. FStream.Write(FBuffer[0], FBufferIndex);
  453. FBufferIndex := 0;
  454. end;
  455. procedure TStreamWriter.OwnStream;
  456. begin
  457. FOwnsStream := True;
  458. end;
  459. procedure TStreamWriter.Write(const Value: string);
  460. begin
  461. WriteBytes(FEncoding.GetBytes(Value));
  462. end;
  463. procedure TStreamWriter.WriteBytes(Bytes: TBytes);
  464. var
  465. ByteIndex: Integer;
  466. WriteLen: Integer;
  467. begin
  468. ByteIndex := 0;
  469. while ByteIndex < Length(Bytes) do
  470. begin
  471. WriteLen := Length(Bytes) - ByteIndex;
  472. if WriteLen > Length(FBuffer) - FBufferIndex then
  473. WriteLen := Length(FBuffer) - FBufferIndex;
  474. Move(Bytes[ByteIndex], FBuffer[FBufferIndex], WriteLen);
  475. Inc(FBufferIndex, WriteLen);
  476. Inc(ByteIndex, WriteLen);
  477. if FBufferIndex >= Length(FBuffer) then
  478. Flush;
  479. end;
  480. if FAutoFlush then
  481. Flush;
  482. end;
  483. procedure TStreamWriter.Write(const aFormat: string; Args: array of const);
  484. begin
  485. WriteBytes(FEncoding.GetBytes(Format(aFormat, Args)));
  486. end;
  487. procedure TStreamWriter.Write(Value: Single);
  488. begin
  489. WriteBytes(FEncoding.GetBytes(FloatToStr(Value)));
  490. end;
  491. procedure TStreamWriter.Write(Value: Double);
  492. begin
  493. WriteBytes(FEncoding.GetBytes(FloatToStr(Value)));
  494. end;
  495. procedure TStreamWriter.Write(Value: Integer);
  496. begin
  497. WriteBytes(FEncoding.GetBytes(IntToStr(Value)));
  498. end;
  499. procedure TStreamWriter.Write(Value: Char);
  500. begin
  501. WriteBytes(FEncoding.GetBytes(Value));
  502. end;
  503. procedure TStreamWriter.Write(Value: TObject);
  504. begin
  505. WriteBytes(FEncoding.GetBytes(Value.ToString));
  506. end;
  507. procedure TStreamWriter.Write(Value: Int64);
  508. begin
  509. WriteBytes(FEncoding.GetBytes(IntToStr(Value)));
  510. end;
  511. procedure TStreamWriter.Write(Value: Boolean);
  512. begin
  513. WriteBytes(FEncoding.GetBytes(BoolToStr(Value, True)));
  514. end;
  515. procedure TStreamWriter.WriteLine(Value: Double);
  516. begin
  517. WriteBytes(FEncoding.GetBytes(FloatToStr(Value) + FNewLine));
  518. end;
  519. procedure TStreamWriter.WriteLine(Value: Integer);
  520. begin
  521. WriteBytes(FEncoding.GetBytes(IntToStr(Value) + FNewLine));
  522. end;
  523. procedure TStreamWriter.WriteLine;
  524. begin
  525. WriteBytes(FEncoding.GetBytes(FNewLine));
  526. end;
  527. procedure TStreamWriter.WriteLine(Value: Boolean);
  528. begin
  529. WriteBytes(FEncoding.GetBytes(BoolToStr(Value, True) + FNewLine));
  530. end;
  531. procedure TStreamWriter.WriteLine(Value: Char);
  532. begin
  533. WriteBytes(FEncoding.GetBytes(Value));
  534. WriteBytes(FEncoding.GetBytes(FNewLine));
  535. end;
  536. procedure TStreamWriter.WriteLine(Value: Int64);
  537. begin
  538. WriteBytes(FEncoding.GetBytes(IntToStr(Value) + FNewLine));
  539. end;
  540. procedure TStreamWriter.WriteLine(const aFormat: string; Args: array of const);
  541. begin
  542. WriteBytes(FEncoding.GetBytes(Format(aFormat, Args) + FNewLine));
  543. end;
  544. procedure TStreamWriter.WriteLine(Value: TObject);
  545. begin
  546. WriteBytes(FEncoding.GetBytes(Value.ToString + FNewLine));
  547. end;
  548. procedure TStreamWriter.WriteLine(Value: Single);
  549. begin
  550. WriteBytes(FEncoding.GetBytes(FloatToStr(Value) + FNewLine));
  551. end;
  552. procedure TStreamWriter.WriteLine(const Value: string);
  553. begin
  554. WriteBytes(FEncoding.GetBytes(Value + FNewLine));
  555. end;
  556. {$ENDIF FPC}
  557. {other functions}
  558. function CreateDummyFile(const aFilename : string; const aSize : Int64 ) : Boolean;
  559. var
  560. fs : TFileStream;
  561. i : Integer;
  562. buf : string;
  563. Begin
  564. Result := False;
  565. fs := TFileStream.Create(aFilename,fmCreate);
  566. buf := 'A';
  567. try
  568. fs.Seek(0, soBeginning);
  569. for i := 0 to aSize do fs.Write(buf[1], Length(buf));
  570. finally
  571. fs.Free;
  572. end;
  573. Result := FileExists(aFilename);
  574. End;
  575. procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
  576. var
  577. fs, ss: TFileStream;
  578. cnt : integer;
  579. splitname: string;
  580. begin
  581. fs := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyWrite) ;
  582. try
  583. for cnt := 1 to Trunc(fs.Size / aSplitByteSize) + 1 do
  584. begin
  585. splitname := ChangeFileExt(aFileName, Format('%s%.3d', ['.',cnt])) ;
  586. ss := TFileStream.Create(splitname, fmCreate or fmShareExclusive) ;
  587. try
  588. if fs.Size - fs.Position < aSplitByteSize then
  589. aSplitByteSize := fs.Size - fs.Position;
  590. ss.CopyFrom(fs, aSplitByteSize) ;
  591. finally
  592. ss.Free;
  593. end;
  594. end;
  595. finally
  596. fs.Free;
  597. end;
  598. end;
  599. procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string);
  600. var
  601. fs, ss: TFileStream;
  602. cnt: integer;
  603. splitfilename : string;
  604. begin
  605. cnt := 1;
  606. splitfilename := aFirstSplitFileName;
  607. fs := TFileStream.Create(aOutFileName, fmCreate or fmShareExclusive) ;
  608. try
  609. while FileExists(splitfilename) do
  610. begin
  611. ss := TFileStream.Create(splitfilename, fmOpenRead or fmShareDenyWrite) ;
  612. try
  613. fs.CopyFrom(ss, 0) ;
  614. finally
  615. ss.Free;
  616. end;
  617. Inc(cnt) ;
  618. splitfilename := ChangeFileExt(aFirstSplitFileName, Format('%s%.3d', ['.',cnt])) ;
  619. end;
  620. finally
  621. fs.Free;
  622. end;
  623. end;
  624. procedure MergeFiles(aFilenames : array of string; const aOutFileName : string);
  625. var
  626. filename : string;
  627. fs,
  628. ss : TFileStream;
  629. begin
  630. fs := TFileStream.Create(aOutFileName,fmCreate or fmShareExclusive) ;
  631. try
  632. for filename in aFilenames do
  633. begin
  634. if not FileExists(filename) then raise Exception.CreateFmt('Merge file %s not found!',[filename]);
  635. ss := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite) ;
  636. try
  637. fs.CopyFrom(ss,0);
  638. finally
  639. ss.Free;
  640. end;
  641. end;
  642. finally
  643. fs.Free;
  644. end;
  645. end;
  646. function IsFileInUse(const aFileName : string) : Boolean;
  647. {$IF NOT Defined(LINUX) AND NOT Defined(MACOS)}
  648. var
  649. HFileRes: HFILE;
  650. begin
  651. Result := False;
  652. if not FileExists(aFileName) then Exit;
  653. try
  654. HFileRes := CreateFile(PChar(aFileName),
  655. GENERIC_READ or GENERIC_WRITE
  656. ,0
  657. ,nil
  658. ,OPEN_EXISTING
  659. ,FILE_ATTRIBUTE_NORMAL
  660. ,0);
  661. Result := (HFileRes = INVALID_HANDLE_VALUE);
  662. if not(Result) then begin
  663. CloseHandle(HFileRes);
  664. end;
  665. except
  666. Result := True;
  667. end;
  668. end;
  669. {$ELSE}
  670. var
  671. fs : TFileStream;
  672. begin
  673. try
  674. fs := TFileStream.Create(aFileName, fmOpenReadWrite, fmShareExclusive);
  675. Result := True;
  676. fs.Free;
  677. except
  678. Result := False;
  679. end;
  680. end;
  681. {$ENDIF}
  682. procedure FileReplaceText(const aFileName, aSearchText, AReplaceText : string);
  683. var
  684. fs: TFileStream;
  685. S: string;
  686. begin
  687. fs := TFileStream.Create(aFileName, fmOpenread or fmShareDenyNone);
  688. try
  689. SetLength(S, fs.Size);
  690. fs.ReadBuffer(S[1], fs.Size);
  691. finally
  692. fs.Free;
  693. end;
  694. S := StringReplace(S, aSearchText, AReplaceText, [rfReplaceAll, rfIgnoreCase]);
  695. fs := TFileStream.Create(aFileName, fmCreate);
  696. try
  697. fs.WriteBuffer(S[1], Length(S));
  698. finally
  699. fs.Free;
  700. end;
  701. end;
  702. function FileSearchText(const aFileName, SearchText: string; caseSensitive : Boolean): Longint;
  703. const
  704. BufferSize = $8001;
  705. var
  706. pBuf, pEnd, pScan, pPos: PAnsiChar;
  707. filesize: LongInt;
  708. bytesRemaining: LongInt;
  709. bytesToRead: Integer;
  710. F: file;
  711. SearchFor: PAnsiChar;
  712. oldMode: Word;
  713. begin
  714. Result := -1;
  715. if (Length(SearchText) = 0) or (Length(aFileName) = 0) then Exit;
  716. SearchFor := nil;
  717. pBuf := nil;
  718. AssignFile(F, aFileName);
  719. oldMode := FileMode;
  720. FileMode := 0;
  721. Reset(F, 1);
  722. FileMode := oldMode;
  723. try
  724. {$IFDEF FPC}
  725. SearchFor := PChar(StrAlloc(Length(SearchText) + 1));
  726. {$ELSE}
  727. {$IFDEF DELPHI2010_UP}
  728. SearchFor := PAnsiChar(StrAlloc(Length(SearchText) + 1));
  729. {$ELSE}
  730. SearchFor := StrAlloc(Length(SearchText) + 1);
  731. {$ENDIF}
  732. {$ENDIF FPC}
  733. StrPCopy(SearchFor, SearchText);
  734. {$IFDEF FPC}
  735. if not caseSensitive then UpperCase(SearchFor);
  736. {$ELSE}
  737. if not caseSensitive then AnsiUpper(SearchFor);
  738. {$ENDIF}
  739. GetMem(pBuf, BufferSize);
  740. filesize := System.Filesize(F);
  741. bytesRemaining := filesize;
  742. pPos := nil;
  743. while bytesRemaining > 0 do
  744. begin
  745. if bytesRemaining >= BufferSize then bytesToRead := Pred(BufferSize)
  746. else bytesToRead := bytesRemaining;
  747. BlockRead(F, pBuf^, bytesToRead, bytesToRead);
  748. pEnd := @pBuf[bytesToRead];
  749. pEnd^ := #0;
  750. pScan := pBuf;
  751. while pScan < pEnd do
  752. begin
  753. {$IFDEF FPC}
  754. if not caseSensitive then UpperCase(pScan);
  755. {$ELSE}
  756. if not caseSensitive then AnsiUpper(pScan);
  757. {$ENDIF}
  758. pPos := StrPos(pScan, SearchFor);
  759. if pPos <> nil then
  760. begin
  761. Result := FileSize - bytesRemaining +
  762. Longint(pPos) - Longint(pBuf);
  763. Break;
  764. end;
  765. pScan := StrEnd(pScan);
  766. Inc(pScan);
  767. end;
  768. if pPos <> nil then Break;
  769. bytesRemaining := bytesRemaining - bytesToRead;
  770. if bytesRemaining > 0 then
  771. begin
  772. Seek(F, FilePos(F) - Length(SearchText));
  773. bytesRemaining := bytesRemaining + Length(SearchText);
  774. end;
  775. end;
  776. finally
  777. CloseFile(F);
  778. if SearchFor <> nil then StrDispose(SearchFor);
  779. if pBuf <> nil then FreeMem(pBuf, BufferSize);
  780. end;
  781. end;
  782. {$IFDEF MSWINDOWS}
  783. function GetLastAccessTime(const aFileName: string): TDateTime;
  784. var
  785. ffd: TWin32FindData;
  786. dft: DWORD;
  787. lft: TFileTime;
  788. h: THandle;
  789. begin
  790. {$IFDEF FPC}
  791. h := FindFirstFile(PAnsiChar(aFileName), ffd);
  792. {$ELSE}
  793. h := FindFirstFile(PChar(aFileName), ffd);
  794. {$ENDIF}
  795. if (INVALID_HANDLE_VALUE <> h) then
  796. begin
  797. FindClose(h);
  798. FileTimeToLocalFileTime(ffd.ftLastAccessTime, lft);
  799. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  800. Result := FileDateToDateTime(dft);
  801. end;
  802. end;
  803. function GetCreationTime(const aFilename : string): TDateTime;
  804. var
  805. ffd: TWin32FindData;
  806. dft: DWORD;
  807. lft: TFileTime;
  808. h: THandle;
  809. begin
  810. {$IFDEF FPC}
  811. h := FindFirstFile(PAnsiChar(aFileName), ffd);
  812. {$ELSE}
  813. h := FindFirstFile(PChar(aFileName), ffd);
  814. {$ENDIF}
  815. if (INVALID_HANDLE_VALUE <> h) then
  816. begin
  817. FindClose(h);
  818. FileTimeToLocalFileTime(ffd.ftCreationTime, lft);
  819. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  820. Result := FileDateToDateTime(dft);
  821. end;
  822. end;
  823. function GetLastWriteTime(const aFileName : string): TDateTime;
  824. var
  825. ffd: TWin32FindData;
  826. dft: DWORD;
  827. lft: TFileTime;
  828. h: THandle;
  829. begin
  830. {$IFDEF FPC}
  831. h := FindFirstFile(PAnsiChar(aFileName), ffd);
  832. {$ELSE}
  833. h := FindFirstFile(PChar(aFileName), ffd);
  834. {$ENDIF}
  835. if (INVALID_HANDLE_VALUE <> h) then
  836. begin
  837. FindClose(h);
  838. FileTimeToLocalFileTime(ffd.ftLastWriteTime, lft);
  839. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  840. Result := FileDateToDateTime(dft);
  841. end;
  842. end;
  843. {$ELSE}
  844. function GetLastAccessTime(const aFileName: string): TDateTime;
  845. var
  846. info : stat;
  847. begin
  848. Result := 0;
  849. if fpstat(aFileName,info) <> 0 then
  850. begin
  851. Result := info.st_atime;
  852. end;
  853. end;
  854. function GetCreationTime(const aFilename : string): TDateTime;
  855. var
  856. info : stat;
  857. begin
  858. Result := 0;
  859. if fpstat(aFileName,info) <> 0 then
  860. begin
  861. Result := info.st_ctime;
  862. end;
  863. end;
  864. function GetLastWriteTime(const aFileName : string): TDateTime;
  865. var
  866. info : stat;
  867. begin
  868. Result := 0;
  869. if fpstat(aFileName,info) <> 0 then
  870. begin
  871. Result := info.st_mtime;
  872. end;
  873. end;
  874. {$ENDIF}
  875. {$IFDEF FPC}
  876. function FindDelimiter(const Delimiters, S: string; StartIdx: Integer = 1): Integer;
  877. var
  878. Stop: Boolean;
  879. Len: Integer;
  880. begin
  881. Result := 0;
  882. Len := S.Length;
  883. Stop := False;
  884. while (not Stop) and (StartIdx <= Len) do
  885. if IsDelimiter(Delimiters, S, StartIdx) then
  886. begin
  887. Result := StartIdx;
  888. Stop := True;
  889. end
  890. else
  891. Inc(StartIdx);
  892. end;
  893. {$ENDIF}
  894. {$IFDEF MSWINDOWS}
  895. function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
  896. var
  897. LFileTime: TFileTime;
  898. SysTime: TSystemTime;
  899. begin
  900. Result.dwLowDateTime := 0;
  901. Result.dwLowDateTime := 0;
  902. DecodeDateTime(DateTime, SysTime.wYear, SysTime.wMonth, SysTime.wDay,
  903. SysTime.wHour, SysTime.wMinute, SysTime.wSecond, SysTime.wMilliseconds);
  904. if SystemTimeToFileTime(SysTime, LFileTime) then
  905. if UseLocalTimeZone then
  906. LocalFileTimeToFileTime(LFileTime, Result)
  907. else
  908. Result := LFileTime;
  909. end;
  910. {$ENDIF}
  911. {$If Defined(FPC) AND Defined(LINUX)}
  912. function ConvertDateTimeToFileTime(const DateTime: TDateTime; const UseLocalTimeZone: Boolean): TFileTime;
  913. begin
  914. { Use the time zone if necessary }
  915. if not UseLocalTimeZone then
  916. Result := DateTimeToFileDate(DateTime)
  917. else
  918. Result := DateTimeToFileDate(DateTime);
  919. end;
  920. {$ENDIF}
  921. {$IFDEF POSIX}
  922. class function TDirectory.ConvertDateTimeToFileTime(const DateTime: TDateTime;
  923. const UseLocalTimeZone: Boolean): time_t;
  924. begin
  925. { Use the time zone if necessary }
  926. if not UseLocalTimeZone then
  927. Result := DateTimeToFileDate(TTimeZone.Local.ToLocalTime(DateTime))
  928. else
  929. Result := DateTimeToFileDate(DateTime);
  930. end;
  931. {$ENDIF}
  932. procedure SetDateTimeInfo(const Path: string; const CreationTime, LastAccessTime, LastWriteTime: PDateTime; const UseLocalTimeZone: Boolean);
  933. {$IFDEF MSWINDOWS}
  934. var
  935. LFileHnd: THandle;
  936. LFileAttr: Cardinal;
  937. LFileCreationTime: PFileTime;
  938. LFileLastAccessTime: PFileTime;
  939. LFileLastWriteTime: PFileTime;
  940. begin
  941. // establish what date-times must be set to the directory
  942. LFileHnd := 0;
  943. LFileCreationTime := nil;
  944. LFileLastAccessTime := nil;
  945. LFileLastWriteTime := nil;
  946. try
  947. try
  948. if Assigned(CreationTime) then
  949. begin
  950. New(LFileCreationTime);
  951. LFileCreationTime^ := ConvertDateTimeToFileTime(CreationTime^, UseLocalTimeZone);
  952. end;
  953. if Assigned(LastAccessTime) then
  954. begin
  955. New(LFileLastAccessTime);
  956. LFileLastAccessTime^ := ConvertDateTimeToFileTime(LastAccessTime^, UseLocalTimeZone);
  957. end;
  958. if Assigned(LastWriteTime) then
  959. begin
  960. New(LFileLastWriteTime);
  961. LFileLastWriteTime^ := ConvertDateTimeToFileTime(LastWriteTime^, UseLocalTimeZone);
  962. end;
  963. // determine if Path points to a directory or a file
  964. SetLastError(ERROR_SUCCESS);
  965. LFileAttr := FileGetAttr(Path);
  966. if LFileAttr and faDirectory <> 0 then
  967. LFileAttr := FILE_FLAG_BACKUP_SEMANTICS
  968. else
  969. LFileAttr := FILE_ATTRIBUTE_NORMAL;
  970. // set the new date-times to the directory or file
  971. LFileHnd := CreateFile(PChar(Path), GENERIC_WRITE, FILE_SHARE_WRITE, nil,
  972. OPEN_EXISTING, LFileAttr, 0);
  973. if LFileHnd <> INVALID_HANDLE_VALUE then
  974. SetFileTime(LFileHnd, LFileCreationTime, LFileLastAccessTime, LFileLastWriteTime);
  975. except
  976. on E: EConvertError do
  977. raise EArgumentOutOfRangeException.Create(E.Message);
  978. end;
  979. finally
  980. CloseHandle(LFileHnd);
  981. SetLastError(ERROR_SUCCESS);
  982. Dispose(LFileCreationTime);
  983. Dispose(LFileLastAccessTime);
  984. Dispose(LFileLastWriteTime);
  985. end;
  986. end;
  987. {$ENDIF}
  988. {$IFDEF POSIX}
  989. var
  990. LFileName: Pointer;
  991. LStatBuf: _stat;
  992. LBuf: utimbuf;
  993. ErrCode: Integer;
  994. M: TMarshaller;
  995. begin
  996. { Do nothing if no date/time passed. Ignore CreationTime. Unixes do not support creation times for files. }
  997. if (LastAccessTime = nil) and (LastWriteTime = nil) then
  998. Exit;
  999. LFileName := M.AsAnsi(Path, CP_UTF8).ToPointer;
  1000. { Obtain the file times. lstat may fail }
  1001. if ((LastAccessTime = nil) or (LastWriteTime = nil)) then
  1002. begin
  1003. ErrCode := stat(LFileName, LStatBuf);
  1004. { Fail if we can't access the file properly }
  1005. if ErrCode <> 0 then
  1006. Exit; // Fail here prematurely. Do not chnage file times if we failed to fetch the old ones.
  1007. end;
  1008. try
  1009. { Preserve of set the new value }
  1010. if LastAccessTime <> nil then
  1011. LBuf.actime := ConvertDateTimeToFileTime(LastAccessTime^, UseLocalTimeZone)
  1012. else
  1013. LBuf.actime := LStatBuf.st_atime;
  1014. { Preserve of set the new value }
  1015. if LastWriteTime <> nil then
  1016. LBuf.modtime := ConvertDateTimeToFileTime(LastWriteTime^, UseLocalTimeZone)
  1017. else
  1018. LBuf.modtime := LStatBuf.st_mtime;
  1019. { Call utime to set the file times }
  1020. utime(LFileName, LBuf);
  1021. except
  1022. on E: EConvertError do // May rise in ConvertDateTimeToFileTime
  1023. raise EArgumentOutOfRangeException.Create(E.Message);
  1024. end;
  1025. end;
  1026. {$ENDIF}
  1027. {$if Defined(FPC) AND Defined(LINUX)}
  1028. begin
  1029. end;
  1030. {$ENDIF}
  1031. end.