📄 jvfileutil.pas
字号:
{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvFileUtil.PAS, released on 2002-07-04.
The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 2001,2002 SGB Software
All Rights Reserved.
Portions Copyright (c) 1998 Ritting Information Systems
Contributor(s):
Roman Kovbasiouk [roko att users dott sourceforge dott net] (TJvBrowseFolderDlg removal)
Last Modified: 2003-03-17
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
{$I JVCL.INC}
{$I WINDOWSONLY.INC}
unit JvFileUtil;
interface
uses
Windows,
{$IFDEF COMPILER6_UP}
RTLConsts,
{$ENDIF}
Messages, SysUtils, Classes, Consts, Controls {, JvComponent};
procedure CopyFile(const FileName, DestName: string; ProgressControl: TControl);
procedure CopyFileEx(const FileName, DestName: string;
OverwriteReadOnly, ShellDialog: Boolean; ProgressControl: TControl);
procedure MoveFile(const FileName, DestName: TFileName);
procedure MoveFileEx(const FileName, DestName: TFileName; ShellDialog: Boolean);
{$IFDEF COMPILER4_UP}
function GetFileSize(const FileName: string): Int64;
{$ELSE}
function GetFileSize(const FileName: string): Longint;
{$ENDIF}
function FileDateTime(const FileName: string): TDateTime;
function HasAttr(const FileName: string; Attr: Integer): Boolean;
function DeleteFiles(const FileMask: string): Boolean;
function DeleteFilesEx(const FileMasks: array of string): Boolean;
function ClearDir(const Path: string; Delete: Boolean): Boolean;
function NormalDir(const DirName: string): string;
function RemoveBackSlash(const DirName: string): string;
function ValidFileName(const FileName: string): Boolean;
function DirExists(Name: string): Boolean;
procedure ForceDirectories(Dir: string);
function FileLock(Handle: Integer; Offset, LockSize: Longint): Integer;
{$IFDEF COMPILER4_UP} overload; {$ENDIF}
{$IFDEF COMPILER4_UP}
function FileLock(Handle: Integer; Offset, LockSize: Int64): Integer; overload;
{$ENDIF}
function FileUnlock(Handle: Integer; Offset, LockSize: Longint): Integer;
{$IFDEF COMPILER4_UP} overload; {$ENDIF}
{$IFDEF COMPILER4_UP}
function FileUnlock(Handle: Integer; Offset, LockSize: Int64): Integer; overload;
{$ENDIF}
function GetTempDir: string;
function GetWindowsDir: string;
function GetSystemDir: string;
{$IFDEF WIN32}
function ShortToLongFileName(const ShortName: string): string;
function ShortToLongPath(const ShortName: string): string;
function LongToShortFileName(const LongName: string): string;
function LongToShortPath(const LongName: string): string;
procedure CreateFileLink(const FileName, DisplayName: string; Folder: Integer);
procedure DeleteFileLink(const DisplayName: string; Folder: Integer);
{$ENDIF WIN32}
{$IFNDEF COMPILER3_UP}
function IsPathDelimiter(const S: string; Index: Integer): Boolean;
{$ENDIF}
implementation
uses
{$IFDEF WIN32}
{$IFDEF COMPILER3_UP}
ActiveX, ComObj, ShlObj,
{$ELSE}
Ole2,
OleAuto,
{$ENDIF}
{$ENDIF}
{$IFDEF COMPILER5}
FileCtrl,
{$ENDIF}
ShellAPI, Forms,
JvDateUtil, JvVCLUtils, JvProgressUtils;
{$IFDEF WIN32}
//=== TJvFileOperator ========================================================
type
TFileOperation = (foCopy, foDelete, foMove, foRename);
TFileOperFlag = (flAllowUndo, flConfirmMouse, flFilesOnly, flMultiDest,
flNoConfirmation, flNoConfirmMkDir, flRenameOnCollision, flSilent,
flSimpleProgress, flNoErrorUI);
TFileOperFlags = set of TFileOperFlag;
TJvFileOperator = class(TComponent)
private
FAborted: Boolean;
FOperation: TFileOperation;
FOptions: TFileOperFlags;
FProgressTitle: string;
FSource: string;
FDestination: string;
function TaskModalDialog(DialogFunc: Pointer; var DialogData): Boolean;
public
constructor Create(AOwner: TComponent); override;
function Execute: Boolean; virtual;
property Aborted: Boolean read FAborted;
published
property Destination: string read FDestination write FDestination;
property Operation: TFileOperation read FOperation write FOperation
default foCopy;
property Options: TFileOperFlags read FOptions write FOptions
default [flAllowUndo, flNoConfirmMkDir];
property ProgressTitle: string read FProgressTitle write FProgressTitle;
property Source: string read FSource write FSource;
end;
{$IFNDEF COMPILER3_UP}
const
FOF_NOERRORUI = $0400;
{$ENDIF}
constructor TJvFileOperator.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FOptions := [flAllowUndo, flNoConfirmMkDir];
end;
function TJvFileOperator.TaskModalDialog(DialogFunc: Pointer; var DialogData): Boolean;
type
TDialogFunc = function(var DialogData): Integer; stdcall;
var
ActiveWindow: HWND;
WindowList: Pointer;
begin
ActiveWindow := GetActiveWindow;
WindowList := DisableTaskWindows(0);
try
Result := TDialogFunc(DialogFunc)(DialogData) = 0;
finally
EnableTaskWindows(WindowList);
SetActiveWindow(ActiveWindow);
end;
end;
function TJvFileOperator.Execute: Boolean;
const
OperTypes: array [TFileOperation] of UINT =
(FO_COPY, FO_DELETE, FO_MOVE, FO_RENAME);
OperOptions: array [TFileOperFlag] of FILEOP_FLAGS =
(FOF_ALLOWUNDO, FOF_CONFIRMMOUSE, FOF_FILESONLY, FOF_MULTIDESTFILES,
FOF_NOCONFIRMATION, FOF_NOCONFIRMMKDIR, FOF_RENAMEONCOLLISION,
FOF_SILENT, FOF_SIMPLEPROGRESS, FOF_NOERRORUI);
var
OpStruct: TSHFileOpStruct;
Flag: TFileOperFlag;
function AllocFileStr(const S: string): PChar;
var
P: PChar;
begin
Result := nil;
if S <> '' then
begin
Result := StrCopy(StrAlloc(Length(S) + 2), PChar(S));
P := Result;
while P^ <> #0 do
begin
if (P^ = ';') or (P^ = '|') then
P^ := #0;
Inc(P);
end;
Inc(P);
P^ := #0;
end;
end;
begin
FAborted := False;
FillChar(OpStruct, SizeOf(OpStruct), 0);
with OpStruct do
try
if (Application.MainForm <> nil) and
Application.MainForm.HandleAllocated then
Wnd := Application.MainForm.Handle
else
Wnd := Application.Handle;
wFunc := OperTypes[Operation];
pFrom := AllocFileStr(FSource);
pTo := AllocFileStr(FDestination);
fFlags := 0;
for Flag := Low(Flag) to High(Flag) do
if Flag in FOptions then
fFlags := fFlags or OperOptions[Flag];
lpszProgressTitle := PChar(FProgressTitle);
Result := TaskModalDialog(@SHFileOperation, OpStruct);
FAborted := fAnyOperationsAborted;
finally
if pFrom <> nil then
StrDispose(pFrom);
if pTo <> nil then
StrDispose(pTo);
end;
end;
{$ELSE}
function BrowseDirectory(var AFolderName: string; const DlgText: string;
AHelpContext: THelpContext): Boolean;
begin
Result := SelectDirectory(AFolderName, [], AHelpContext);
end;
{$ENDIF WIN32}
function NormalDir(const DirName: string): string;
begin
Result := DirName;
if (Result <> '') and
{$IFDEF COMPILER3_UP}
not (AnsiLastChar(Result)^ in [':', '\']) then
{$ELSE}
not (Result[Length(Result)] in [':', '\']) then
{$ENDIF}
if (Length(Result) = 1) and (UpCase(Result[1]) in ['A'..'Z']) then
Result := Result + ':\'
else
Result := Result + '\';
end;
function RemoveBackSlash(const DirName: string): string;
begin
Result := DirName;
if (Length(Result) > 1) and
{$IFDEF COMPILER3_UP}
(AnsiLastChar(Result)^ = '\') then
{$ELSE}
(Result[Length(Result)] = '\') then
{$ENDIF}
if not ((Length(Result) = 3) and (UpCase(Result[1]) in ['A'..'Z']) and
(Result[2] = ':')) then
Delete(Result, Length(Result), 1);
end;
{$IFDEF WIN32}
function DirExists(Name: string): Boolean;
var
Code: Integer;
begin
Code := GetFileAttributes(PChar(Name));
Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
end;
{$ELSE}
function DirExists(Name: string): Boolean;
var
SR: TSearchRec;
begin
if Name[Length(Name)] = '\' then
Dec(Name[0]);
if (Length(Name) = 2) and (Name[2] = ':') then
Name := Name + '\*.*';
Result := FindFirst(Name, faDirectory, SR) = 0;
Result := Result and (SR.Attr and faDirectory <> 0);
end;
{$ENDIF}
procedure ForceDirectories(Dir: string);
begin
if Length(Dir) = 0 then
Exit;
{$IFDEF COMPILER3_UP}
if (AnsiLastChar(Dir) <> nil) and (AnsiLastChar(Dir)^ = '\') then
{$ELSE}
if Dir[Length(Dir)] = '\' then
{$ENDIF}
Delete(Dir, Length(Dir), 1);
if (Length(Dir) < 3) or DirectoryExists(Dir) or
(ExtractFilePath(Dir) = Dir) then
Exit;
ForceDirectories(ExtractFilePath(Dir));
{$IFDEF WIN32}
CreateDir(Dir);
{$ELSE}
MkDir(Dir);
{$ENDIF}
end;
{$IFDEF WIN32}
procedure CopyMoveFileShell(const FileName, DestName: string; Confirmation,
AllowUndo, MoveFile: Boolean);
begin
with TJvFileOperator.Create(nil) do
try
Source := FileName;
Destination := DestName;
if MoveFile then
begin
if AnsiCompareText(ExtractFilePath(FileName),
ExtractFilePath(DestName)) = 0 then
Operation := foRename
else
Operation := foMove;
end
else
Operation := foCopy;
if not AllowUndo then
Options := Options - [flAllowUndo];
if not Confirmation then
Options := Options + [flNoConfirmation];
if not Execute or Aborted then
SysUtils.Abort;
finally
Free;
end;
end;
{$ENDIF}
procedure CopyFile(const FileName, DestName: string; ProgressControl: TControl);
begin
CopyFileEx(FileName, DestName, False, False, ProgressControl);
end;
procedure CopyFileEx(const FileName, DestName: string;
OverwriteReadOnly, ShellDialog: Boolean; ProgressControl: TControl);
const
ChunkSize = 8192;
var
CopyBuffer: Pointer;
Source, Dest: Integer;
Destination: TFileName;
FSize, BytesCopied, TotalCopied: Longint;
Attr: Integer;
begin
{$IFDEF WIN32}
if NewStyleControls and ShellDialog then
begin
CopyMoveFileShell(FileName, DestName, not OverwriteReadOnly,
False, False);
Exit;
end;
{$ENDIF}
Destination := DestName;
if HasAttr(Destination, faDirectory) then
Destination := NormalDir(Destination) + ExtractFileName(FileName);
GetMem(CopyBuffer, ChunkSize);
try
TotalCopied := 0;
FSize := GetFileSize(FileName);
Source := FileOpen(FileName, fmShareDenyWrite);
if Source < 0 then
raise EFOpenError.CreateFmt(ResStr(SFOpenError), [FileName]);
try
if ProgressControl <> nil then
begin
SetProgressMax(ProgressControl, FSize);
SetProgressMin(ProgressControl, 0);
SetProgressValue(ProgressControl, 0);
end;
ForceDirectories(ExtractFilePath(Destination));
if OverwriteReadOnly then
begin
Attr := FileGetAttr(Destination);
if (Attr >= 0) and ((Attr and faReadOnly) <> 0) then
FileSetAttr(Destination, Attr and not faReadOnly);
end;
Dest := FileCreate(Destination);
if Dest < 0 then
raise EFCreateError.CreateFmt(ResStr(SFCreateError), [Destination]);
try
repeat
BytesCopied := FileRead(Source, CopyBuffer^, ChunkSize);
if BytesCopied = -1 then
raise EReadError.Create(ResStr(SReadError));
TotalCopied := TotalCopied + BytesCopied;
if BytesCopied > 0 then
begin
if FileWrite(Dest, CopyBuffer^, BytesCopied) = -1 then
raise EWriteError.Create(ResStr(SWriteError));
end;
if ProgressControl <> nil then
SetProgressValue(ProgressControl, TotalCopied);
until BytesCopied < ChunkSize;
FileSetDate(Dest, FileGetDate(Source));
finally
FileClose(Dest);
end;
finally
FileClose(Source);
end;
finally
FreeMem(CopyBuffer, ChunkSize);
if ProgressControl <> nil then
SetProgressValue(ProgressControl, 0);
end;
end;
procedure MoveFile(const FileName, DestName: TFileName);
var
Destination: TFileName;
Attr: Integer;
begin
Destination := ExpandFileName(DestName);
if not RenameFile(FileName, Destination) then
begin
Attr := FileGetAttr(FileName);
if Attr < 0 then
Exit;
if (Attr and faReadOnly) <> 0 then
FileSetAttr(FileName, Attr and not faReadOnly);
CopyFile(FileName, Destination, nil);
DeleteFile(FileName);
end;
end;
procedure MoveFileEx(const FileName, DestName: TFileName;
ShellDialog: Boolean);
begin
{$IFDEF WIN32}
if NewStyleControls and ShellDialog then
CopyMoveFileShell(FileName, DestName, False, False, True)
else
{$ENDIF}
MoveFile(FileName, DestName);
end;
{$IFDEF COMPILER4_UP}
function GetFileSize(const FileName: string): Int64;
var
Handle: THandle;
FindData: TWin32FindData;
begin
Handle := FindFirstFile(PChar(FileName), FindData);
if Handle <> INVALID_HANDLE_VALUE then
begin
Windows.FindClose(Handle);
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
begin
Int64Rec(Result).Lo := FindData.nFileSizeLow;
Int64Rec(Result).Hi := FindData.nFileSizeHigh;
Exit;
end;
end;
Result := -1;
end;
{$ELSE}
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);
end;
{$ENDIF COMPILER4_UP}
function FileDateTime(const FileName: string): System.TDateTime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -