所以我有一個“下載”檔案夾,我把我下載的所有東西都放在我的日常作業中。你知道我們總是自動化一切,所以我試圖構建一個簡單的應用程式來每天運行以洗掉超過 30 天的檔案,因為我必須不時手動執行此操作以避免檔案夾變得太大。
這是我的代碼:
function TForm1.deleteOldDownloads: boolean;
var
f: string;
i, d: Integer;
var
sl: tstringlist;
begin
try
FileListBox1.Directory := '\\psf\home\downloads';
FileListBox1.refresh;
sl := tstringlist.create;
for i := 0 to FileListBox1.items.count - 1 do
begin
f := FileListBox1.Directory '\' FileListBox1.items[i];
if fileexists(f) then
d := daysbetween(FileAge(f), now)
else
d := 0;
if d > 30 then // problem is here, d is always a big number, not the actually age of file
sl.Add(f);
end;
if sl.count > 0 then
begin
for i := 0 to sl.count do
begin
f := sl[i];
deletefile(f);
end;
end;
sl.Free;
except
on e: Exception do
begin
end;
end;
問題是“d”變數回傳非常大的數字,如 1397401677,即使檔案只有 1 天。
這里唯一的細節是我在 Parallels 虛擬機中運行 Windows,并且“\psf\home\downloads”檔案夾在 Mac 上,但我可以使用 Windows 資源管理器正常訪問此檔案夾,因此對于 Delphi 來說就像一個常規的本地檔案夾。
我錯過了什么?
uj5u.com熱心網友回復:
你閱讀檔案的FileAge?在編程學校的第一天,你會學到“當你開始使用一個新的函式或 API 時,你首先要閱讀它的檔案”。在這種情況下,函式的檔案說
FileAge不推薦使用[one-argument] 多載版本。
所以你正在使用一個你不應該使用的函式。
盡管如此,這個功能應該仍然有效。
但是你期望它回傳什么?好吧,顯然檔案說它應該回傳的內容:
第一個多載回傳一個整數,表示檔案的作業系統時間戳。稍后可以
TDateTime使用該FileDateToDateTime函式將結果轉換為 a 。
但是當您在 in 中使用它時DaysBetween,您會認為它已經是一個TDateTime!
為什么 FileAge 回傳意外值?
不是。它可能正在回傳其檔案所說的應該回傳的內容。
uj5u.com熱心網友回復:
您使用的舊版本FileAge()以 DOS 數字格式回傳時間戳,但您將其視為TDateTime,而事實并非如此。正如FileAge檔案所說:
第一個多載回傳一個整數,表示檔案的作業系統時間戳。稍后可以
TDateTime使用該FileDateToDateTime()函式將結果轉換為 a 。
所以,按照檔案說的去做,例如:
var
age: Integer;
age := FileAge(f);
if age <> -1 then
d := DaysBetween(FileDateToDateTime(age), Now)
否則,使用該FileAge()輸出 a的較新版本TDateTime開始,例如:
var
dt: TDateTime;
if FileAge(f, dt) then
d := DaysBetween(dt, Now)
uj5u.com熱心網友回復:
這不是對您問題的直接回答,但我不能將其作為評論發布。所以,問題是,你永遠不應該直接洗掉用戶檔案。如果你犯了錯誤怎么辦?如果您的程式的用戶犯了錯誤怎么辦?始終將檔案洗掉到回收站:
{--------------------------------------------------------------------------------------------------
DELETE FILE
Deletes a file/folder to RecycleBin.
Old name: Trashafile
Note related to UNC: The function won't move a file to the RecycleBin if the file is UNC. MAYBE it was moved to the remote's computer RecycleBin
--------------------------------------------------------------------------------------------------}
function RecycleItem(CONST ItemName: string; CONST DeleteToRecycle: Boolean= TRUE; CONST ShowConfirm: Boolean= TRUE; CONST TotalSilence: Boolean= FALSE): Boolean;
VAR
SHFileOpStruct: TSHFileOpStruct;
begin
FillChar(SHFileOpStruct, SizeOf(SHFileOpStruct), #0);
SHFileOpStruct.wnd := Application.MainForm.Handle; { Others are using 0. But Application.MainForm.Handle is better because otherwise, the 'Are you sure you want to delete' will be hidden under program's window }
SHFileOpStruct.wFunc := FO_DELETE;
SHFileOpStruct.pFrom := PChar(ItemName #0); { ATENTION! This last #0 is MANDATORY. See this for details: http://stackoverflow.com/questions/6332259/i-cannot-delete-files-to-recycle-bin - Although this member is declared as a single null-terminated string, it is actually a buffer that can hold multiple null-delimited file names. Each file name is terminated by a single NULL character. The last file name is terminated with a double NULL character ("\0\0") to indicate the end of the buffer }
SHFileOpStruct.pTo := NIL;
SHFileOpStruct.hNameMappings := NIL;
if DeleteToRecycle
then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_ALLOWUNDO;
if TotalSilence
then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_NO_UI
else
if NOT ShowConfirm
then SHFileOpStruct.fFlags:= SHFileOpStruct.fFlags OR FOF_NOCONFIRMATION;
Result:= SHFileOperation(SHFileOpStruct)= 0;
//DEBUG ONLY if Result<> 0 then Mesaj('last error: ' IntToStr(Result) CRLF 'last error message: ' SysErrorMessage(Result));
//if fos.fAnyOperationsAborted = True then Result:= -1;
end;
此外,您不需要那種過時的控制元件來獲取檔案夾中的檔案。你可以使用這個:
{ FIND FILES }
function ListFilesOf(CONST aFolder, FileType: string; CONST ReturnFullPath, DigSubdirectories: Boolean): TStringList;
{ If DigSubdirectories is false, it will return only the top level files,
else it will return also the files in subdirectories of subdirectories.
If FullPath is true the returned files will have full path.
FileType can be something like '*.*' or '*.exe;*.bin'
Will show also the Hidden/System files.
Source Marco Cantu Delphi 2010 HandBook
// Works with UNC paths}
VAR
i: Integer;
s: string;
SubFolders, filesList: TStringDynArray;
MaskArray: TStringDynArray;
Predicate: TDirectory.TFilterPredicate;
procedure ListFiles(CONST aFolder: string);
VAR strFile: string;
begin
Predicate:=
function(const Path: string; const SearchRec: TSearchRec): Boolean
VAR Mask: string;
begin
for Mask in MaskArray DO
if System.Masks.MatchesMask(SearchRec.Name, Mask)
then EXIT(TRUE);
EXIT(FALSE);
end;
// Long paths will raise an EPathTooLongexception exception, so we simply don't process those folders
if Length(aFolder) > MAXPATH
then exit;
filesList:= TDirectory.GetFiles (aFolder, Predicate);
for strFile in filesList DO
if strFile<> '' { Bug somewhere here: it returns two empty entries ('') here. Maybe the root folder? }
then Result.Add(strFile);
end;
begin
{ I need this in order to prevent the EPathTooLongexception (reported by some users) }
if aFolder.Length >= MAXPATH then
begin
MesajError('Path is longer than ' IntToStr(MAXPATH) ' characters!');
EXIT(NIL);
end;
if NOT System.IOUtils.TDirectory.Exists (aFolder)
then RAISE exception.Create('Folder does not exist! ' CRLF aFolder);
Result:= TStringList.Create;
{ Split FileType in subcomponents }
MaskArray:= System.StrUtils.SplitString(FileType, ';');
{ Search the parent folder }
ListFiles(aFolder);
{ Search in all subfolders }
if DigSubdirectories then
begin
SubFolders:= TDirectory.GetDirectories(aFolder, TSearchOption.soAllDirectories, NIL);
for s in SubFolders DO
begin
if ccIO.DirectoryExists(s) { This solves the problem caused by broken 'Symbolic Link' folders }
then ListFiles(s);
end;
end;
{ Remove full path }
if NOT ReturnFullPath then
for i:= 0 to Result.Count-1 DO
Result[i]:= TPath.GetFileName(Result[i]);
end;
以上代碼來自:https : //github.com/GodModeUser/Delphi-LightSaber
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/350464.html
