ورود

View Full Version : سوال: راه جایگزین برای تابع SetFileTime



persia_hrn
سه شنبه 14 مرداد 1399, 16:33 عصر
سلام خدمت همه اساتید عزیز

سوال اصلی من اینه که آیا راه جایگزینی بجای استفاده از تابع SetFileTime جهت تغییر تاریخهای موجود در فایلها (CreationTime, LastAccessTime, LastWriteTime) وجود دارد ؟

علت این خواسته اینه که قبل از استفاده از این تابع ، مجبوریم زمان رو با تابع DateTimeToFileDate به Integer در 2 رنج Hi , Lo که هرکدوم 16بیته تبدیل کنیم :

function DateTimeToFileDate(DateTime: TDateTime): Integer;
var
Year, Month, Day, Hour, Min, Sec, MSec: Word;
begin
DecodeDate(DateTime, Year, Month, Day);
if (Year < 1980) or (Year > 2099) then Result := 0 else
begin
DecodeTime(DateTime, Hour, Min, Sec, MSec);
LongRec(Result).Lo := (Sec shr 1) or (Min shl 5) or (Hour shl 11);
LongRec(Result).Hi := Day or (Month shl 5) or ((Year - 1980) shl 9);
end;
end;

همینجور که می بینید در اینجا میلی ثانیه از دست میره و همچنین ثانیه تقسیم بر 2 میشه (Sec Shr 1) که خودش یه مشکل ایجاد میکنه (مثلا اگر شما 35 ثانیه رو در نظر بگیرید بعد از تبدیل میشه 34 ثانیه چون تقسیم بر 2 این عدد صحیح نیست و اعشارش از دست میره).

و در نهایت با دستورات زیر میشه تاریخ یک فایل رو تغییر داد :

function MyFileSetDate(Handle: Integer; Age: Integer): Integer;
var
LocalFileTime, FileTime: TFileTime;
begin
Result := 0;
if DosDateTimeToFileTime(LongRec(Age).Hi, LongRec(Age).Lo, LocalFileTime) and
LocalFileTimeToFileTime(LocalFileTime, FileTime) and
SetFileTime(Handle, @FileTime, @FileTime, @FileTime) then Exit;
Result := GetLastError;
end;

خب حالا برای جلوگیری از اینکه میلی ثانیه از دست بره و ثانیه تقسیم به 2 نشه ما میتونیم تابعی بنویسیم که Int64 رو برگردونه ، به اینصورت :

function MyDateTimeToFileDate(DateTime: TDateTime): Int64;
var
Year, Month, Day, Hour, Min, Sec, MSec: Word;
begin
DecodeDate(DateTime, Year, Month, Day);
if (Year < 1980) or (Year > 2099) then Result := 0 else
begin
DecodeTime(DateTime, Hour, Min, Sec, MSec);
Int64Rec(Result).Lo := Msec or (Sec shl 10) or (Min shl 16) or (Hour shl 22);
Int64Rec(Result).Hi := Day or (Month shl 5) or ((Year - 1980) shl 9);
end;
end;

و به اینصورت استفادش کنیم :

function MyFileSetDate(Handle: Integer; Age: Int64): Integer;
var
LocalFileTime, MyFileTime: TFileTime;
begin
Result := 0;
LocalFileTime.dwHighDateTime:=Int64Rec(Age).Hi;
LocalFileTime.dwLowDateTime:=int64rec(Age).Lo;
if LocalFileTimeToFileTime(LocalFileTime, MyFileTime) and SetFileTime(Handle, @MyFileTime, @MyFileTime, @MyFileTime) then
Exit;
Result := GetLastError;
end;

ولی در نهایت به دلیل ساختار تابع SetFileTime تلاشمون نیمه کاره میمونه . چرا که این کار در درایوهایی با FAT32 ارور میده و در درایوهای NTFS انجام میشه ولی تاریخ و ساعتش خیلی اشکال داره !

طبق توضیحات مایکروسافت که لینکشم پایین میذارم ، این تابع 2 متغیر dwLowDateTime و dwHighDateTime از نوع DWord داره .
https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime
(https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime)
این رو میدونم که خود ویندوز زمان ساخته شدن فایل میلی ثانیه رو هم در ساختار فایل درنظر میگیره :

فایل ساخته شده در درایو FAT32 :
151997

فایل ساخته شده در درایو NTFS :
151999

از شما اساتید محترم تقاضا دارم اگر ایرادی در کار من هست بهم اطلاع بدید و یا اگر راه دیگه ای میشناسید که میلی ثانیه رو از دست نده ممنون میشم راهنماییم کنید .

BORHAN TEC
چهارشنبه 07 آبان 1399, 11:51 صبح
با سلام،
میتونید از یونیت IOUtils و قابلیتهای اون استفاده کنید. این یونیت از زمان دلفی 2010 اضافه شده. اگر به این یونیت نگاه کنید رکورد TFile را میبینید که شامل متدهای مختلفی است که برای مسئله ای که مطرح کردید میتوانید از متدهایی که در زیر لیست کرده ام استفاده نمایید:
class procedure SetCreationTime(const Path: string; const CreationTime: TDateTime); inline; static; class procedure SetCreationTimeUtc(const Path: string; const CreationTime: TDateTime); inline; static;
class procedure SetLastAccessTime(const Path: string; const LastAccessTime: TDateTime); inline; static;
class procedure SetLastAccessTimeUtc(const Path: string; const LastAccessTime: TDateTime); inline; static;
class procedure SetLastWriteTime(const Path: string; const LastWriteTime: TDateTime); inline; static;
class procedure SetLastWriteTimeUtc(const Path: string; const LastWriteTime: TDateTime); inline; static;

موفق و سربلند باشید :لبخندساده: