Quick.Files.pas 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. { ***************************************************************************
  2. Copyright (c) 2016-2018 Kike Pérez
  3. Unit : Quick.Files
  4. Description : Files functions
  5. Author : Kike Pérez
  6. Version : 1.0
  7. Created : 09/03/2018
  8. Modified : 14/03/2018
  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. interface
  23. uses
  24. Classes,
  25. System.SysUtils,
  26. Winapi.Windows;
  27. type
  28. TTextFileOperation = (tfOpenRead,tfOpenOverwrite,tfOpenAppend);
  29. TTextStreamFile = class
  30. private
  31. fReadStream : TStreamReader;
  32. fWriteStream : TStreamWriter;
  33. function GetEOF : Boolean;
  34. public
  35. constructor Create(const aFileName : string; aOpenMode : TTextFileOperation);
  36. destructor Destroy; override;
  37. function ReadLn: string; overload;
  38. function ReadLn(out Data: string): Boolean; overload;
  39. procedure WriteLn (const Data : string);
  40. procedure Close;
  41. property EOF: Boolean read GetEOF;
  42. end;
  43. function CreateDummyFile(const aFilename : string; const aSize : Int64) : Boolean;
  44. procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
  45. procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string); overload;
  46. procedure MergeFiles(aFilenames : array of const; const aOutFileName : string); overload;
  47. function IsFileInUse(const aFileName : string) : Boolean;
  48. procedure FileReplaceText(const aFileName, aSearchText, AReplaceText : string);
  49. function FileSearchText(const aFileName, SearchText: string; caseSensitive : Boolean): Longint;
  50. function GetLastAccessTime(const aFileName: string): TDateTime;
  51. function GetCreationTime(const aFilename : string): TDateTime;
  52. function GetLastModificationTime(const aFileName : string): TDateTime;
  53. implementation
  54. { TTextStreamFile }
  55. constructor TTextStreamFile.Create(const aFileName : string; aOpenMode : TTextFileOperation);
  56. var
  57. Append : Boolean;
  58. begin
  59. if aOpenMode = tfOpenRead then fReadStream := TStreamReader.Create(aFileName,True)
  60. else
  61. begin
  62. if aOpenMode = tfOpenAppend then Append := True
  63. else Append := False;
  64. fWriteStream := TStreamWriter.Create(aFileName,Append);
  65. end;
  66. end;
  67. destructor TTextStreamFile.Destroy;
  68. begin
  69. if Assigned(fReadStream) then fReadStream.Free;
  70. if Assigned(fWriteStream) then fWriteStream.Free;
  71. inherited Destroy;
  72. end;
  73. function TTextStreamFile.ReadLn(out Data: string): Boolean;
  74. begin
  75. Data := fReadStream.ReadLine;
  76. Result := Data <> '';
  77. end;
  78. function TTextStreamFile.ReadLn: string;
  79. begin
  80. Result := fReadStream.ReadLine;
  81. end;
  82. procedure TTextStreamFile.WriteLn (const Data : string);
  83. begin
  84. fWriteStream.WriteLine(Data);
  85. end;
  86. function TTextStreamFile.GetEOF : Boolean;
  87. begin
  88. Result := fReadStream.EndOfStream;
  89. end;
  90. procedure TTextStreamFile.Close;
  91. begin
  92. if Assigned(fReadStream) then fReadStream.Close;
  93. if Assigned(fWriteStream) then fWriteStream.Close;
  94. end;
  95. {other functions}
  96. function CreateDummyFile(const aFilename : string; const aSize : Int64 ) : Boolean;
  97. var
  98. fs : TFileStream;
  99. i : Integer;
  100. Begin
  101. Result := False;
  102. fs := TFileStream.Create(aFilename,fmCreate);
  103. try
  104. for i := 0 to aSize do fs.Write('A',1);
  105. finally
  106. fs.Free;
  107. end;
  108. Result := FileExists(aFilename);
  109. End;
  110. procedure SplitFile(const aFileName : string; aSplitByteSize : Int64);
  111. var
  112. fs, ss: TFileStream;
  113. cnt : integer;
  114. splitname: string;
  115. begin
  116. fs := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyWrite) ;
  117. try
  118. for cnt := 1 to Trunc(fs.Size / aSplitByteSize) + 1 do
  119. begin
  120. splitname := ChangeFileExt(aFileName, Format('%s%.3d', ['.',cnt])) ;
  121. ss := TFileStream.Create(splitname, fmCreate or fmShareExclusive) ;
  122. try
  123. if fs.Size - fs.Position < aSplitByteSize then
  124. aSplitByteSize := fs.Size - fs.Position;
  125. ss.CopyFrom(fs, aSplitByteSize) ;
  126. finally
  127. ss.Free;
  128. end;
  129. end;
  130. finally
  131. fs.Free;
  132. end;
  133. end;
  134. procedure MergeFiles(const aFirstSplitFileName, aOutFileName : string);
  135. var
  136. fs, ss: TFileStream;
  137. cnt: integer;
  138. begin
  139. cnt := 1;
  140. fs := TFileStream.Create(aOutFileName, fmCreate or fmShareExclusive) ;
  141. try
  142. while FileExists(aFirstSplitFileName) do
  143. begin
  144. ss := TFileStream.Create(aFirstSplitFileName, fmOpenRead or fmShareDenyWrite) ;
  145. try
  146. fs.CopyFrom(ss, 0) ;
  147. finally
  148. ss.Free;
  149. end;
  150. Inc(cnt) ;
  151. aFirstSplitFileName := ChangeFileExt(aFirstSplitFileName, Format('%s%.3d', ['.',cnt])) ;
  152. end;
  153. finally
  154. fs.Free;
  155. end;
  156. end;
  157. procedure MergeFiles(aFilenames : array of const; const aOutFileName : string);
  158. var
  159. filename : string;
  160. fs,
  161. ss : TFileStream;
  162. begin
  163. fs := TFileStream.Create(aOutFileName,fmCreate or fmShareExclusive) ;
  164. try
  165. for filename in aFilenames do
  166. begin
  167. if not FileExists(filename) then raise Exception.CreateFmt('Merge file %s not found!',[filename]);
  168. ss := TFileStream.Create(filename, fmOpenRead or fmShareDenyWrite) ;
  169. try
  170. fs.CopyFrom(ss,0);
  171. finally
  172. ss.Free;
  173. end;
  174. end;
  175. finally
  176. fs.Free;
  177. end;
  178. end;
  179. function IsFileInUse(const aFileName : string) : Boolean;
  180. var
  181. HFileRes: HFILE;
  182. begin
  183. Result := False;
  184. if not FileExists(aFileName) then Exit;
  185. try
  186. HFileRes := CreateFile(PChar(aFileName),
  187. GENERIC_READ or GENERIC_WRITE
  188. ,0
  189. ,nil
  190. ,OPEN_EXISTING
  191. ,FILE_ATTRIBUTE_NORMAL
  192. ,0);
  193. Result := (HFileRes = INVALID_HANDLE_VALUE);
  194. if not(Result) then begin
  195. CloseHandle(HFileRes);
  196. end;
  197. except
  198. Result := True;
  199. end;
  200. end;
  201. procedure FileReplaceText(const aFileName, aSearchText, AReplaceText : string);
  202. var
  203. fs: TFileStream;
  204. S: string;
  205. begin
  206. fs := TFileStream.Create(aFileName, fmOpenread or fmShareDenyNone);
  207. try
  208. SetLength(S, fs.Size);
  209. fs.ReadBuffer(S[1], fs.Size);
  210. finally
  211. fs.Free;
  212. end;
  213. S := StringReplace(S, aSearchText, AReplaceText, [rfReplaceAll, rfIgnoreCase]);
  214. fs := TFileStream.Create(aFileName, fmCreate);
  215. try
  216. fs.WriteBuffer(S[1], Length(S));
  217. finally
  218. fs.Free;
  219. end;
  220. end;
  221. function FileSearchText(const aFileName, SearchText: string; caseSensitive : Boolean): Longint;
  222. const
  223. BufferSize = $8001;
  224. var
  225. {$IF CompilerVersion < 20}
  226. pBuf, pEnd, pScan, pPos: PChar;
  227. {$ELSE}
  228. pBuf, pEnd, pScan, pPos: PAnsiChar;
  229. {$ENDIF}
  230. filesize: LongInt;
  231. bytesRemaining: LongInt;
  232. bytesToRead: Integer;
  233. F: file;
  234. {$IF CompilerVersion < 20}
  235. SearchFor: PChar;
  236. {$ELSE}
  237. SearchFor: PAnsiChar;
  238. {$ENDIF}
  239. oldMode: Word;
  240. begin
  241. Result := -1;
  242. if (Length(SearchText) = 0) or (Length(aFileName) = 0) then Exit;
  243. SearchFor := nil;
  244. pBuf := nil;
  245. AssignFile(F, aFileName);
  246. oldMode := FileMode;
  247. FileMode := 0;
  248. Reset(F, 1);
  249. FileMode := oldMode;
  250. try
  251. {$IF CompilerVersion < 20}
  252. SearchFor := StrAlloc(Length(SearchText) + 1);
  253. {$ELSE}
  254. SearchFor := PAnsiChar(StrAlloc(Length(SearchText) + 1));
  255. {$ENDIF}
  256. StrPCopy(SearchFor, SearchText);
  257. if not caseSensitive then AnsiUpper(SearchFor);
  258. GetMem(pBuf, BufferSize);
  259. filesize := System.Filesize(F);
  260. bytesRemaining := filesize;
  261. pPos := nil;
  262. while bytesRemaining > 0 do
  263. begin
  264. if bytesRemaining >= BufferSize then bytesToRead := Pred(BufferSize)
  265. else bytesToRead := bytesRemaining;
  266. BlockRead(F, pBuf^, bytesToRead, bytesToRead);
  267. pEnd := @pBuf[bytesToRead];
  268. pEnd^ := #0;
  269. pScan := pBuf;
  270. while pScan < pEnd do
  271. begin
  272. if not caseSensitive then AnsiUpper(pScan);
  273. pPos := StrPos(pScan, SearchFor);
  274. if pPos <> nil then
  275. begin
  276. Result := FileSize - bytesRemaining +
  277. Longint(pPos) - Longint(pBuf);
  278. Break;
  279. end;
  280. pScan := StrEnd(pScan);
  281. Inc(pScan);
  282. end;
  283. if pPos <> nil then Break;
  284. bytesRemaining := bytesRemaining - bytesToRead;
  285. if bytesRemaining > 0 then
  286. begin
  287. Seek(F, FilePos(F) - Length(SearchText));
  288. bytesRemaining := bytesRemaining + Length(SearchText);
  289. end;
  290. end;
  291. finally
  292. CloseFile(F);
  293. if SearchFor <> nil then StrDispose(SearchFor);
  294. if pBuf <> nil then FreeMem(pBuf, BufferSize);
  295. end;
  296. end;
  297. function GetLastAccessTime(const aFileName: string): TDateTime;
  298. var
  299. ffd: TWin32FindData;
  300. dft: DWORD;
  301. lft: TFileTime;
  302. h: THandle;
  303. begin
  304. h := FindFirstFile(PChar(aFileName), ffd);
  305. if (INVALID_HANDLE_VALUE <> h) then
  306. begin
  307. FindClose(h);
  308. FileTimeToLocalFileTime(ffd.ftLastAccessTime, lft);
  309. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  310. Result := FileDateToDateTime(dft);
  311. end;
  312. end;
  313. function GetCreationTime(const aFilename : string): TDateTime;
  314. var
  315. ffd: TWin32FindData;
  316. dft: DWORD;
  317. lft: TFileTime;
  318. h: THandle;
  319. begin
  320. h := FindFirstFile(PChar(aFilename), ffd);
  321. if (INVALID_HANDLE_VALUE <> h) then
  322. begin
  323. FindClose(h);
  324. FileTimeToLocalFileTime(ffd.ftCreationTime, lft);
  325. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  326. Result := FileDateToDateTime(dft);
  327. end;
  328. end;
  329. function GetLastModificationTime(const aFileName : string): TDateTime;
  330. var
  331. ffd: TWin32FindData;
  332. dft: DWORD;
  333. lft: TFileTime;
  334. h: THandle;
  335. begin
  336. h := FindFirstFile(PChar(aFilename), ffd);
  337. if (INVALID_HANDLE_VALUE <> h) then
  338. begin
  339. FindClose(h);
  340. FileTimeToLocalFileTime(ffd.ftLastWriteTime, lft);
  341. FileTimeToDosDateTime(lft, LongRec(dft).Hi, LongRec(dft).Lo);
  342. Result := FileDateToDateTime(dft);
  343. end;
  344. end;
  345. end.