سلام خدمت همه اساتید عزیز
سوال اصلی من اینه که آیا راه جایگزینی بجای استفاده از تابع 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
این رو میدونم که خود ویندوز زمان ساخته شدن فایل میلی ثانیه رو هم در ساختار فایل درنظر میگیره :
فایل ساخته شده در درایو FAT32 :
FAT32.jpg
فایل ساخته شده در درایو NTFS :
NTFS.jpg
از شما اساتید محترم تقاضا دارم اگر ایرادی در کار من هست بهم اطلاع بدید و یا اگر راه دیگه ای میشناسید که میلی ثانیه رو از دست نده ممنون میشم راهنماییم کنید .