#delphi #winapi
#delphi #winapi
Вопрос:
Хотел уточнить у вас, экспертов, есть ли какие-либо недостатки в этой функции. Будет ли это работать должным образом в различных ОС Windows? Я использую Delphi Seattle (32 и 64-разрядные EXE-файлы). Я использую это вместо Findfirst из-за его скорости.
function GetFileDetailsFromAttr(pFileName:WideString):int64;
var
wfad: TWin32FileAttributeData;
wSize:LARGE_INTEGER ;
begin
Result:=0 ;
if not GetFileAttributesEx(pwidechar(pFileName), GetFileExInfoStandard,@wfad) then
exit;
wSize.HighPart:=wfad.nFileSizeHigh ;
wSize.LowPart:=wfad.nFileSizeLow ;
result:=wsize.QuadPart ;
end;
Типичные примеры, показанные в Google с помощью этой команды, не работают для размера файла > 9 ГБ
function GetFileAttributesEx():Int64 using
begin
...
result:=((amp;wfad.nFileSizeHigh) or (amp;wfad.nFileSizeLow))
Комментарии:
1. Второй пример неверен, поскольку он не сдвигает биты
nFileSizeHigh
, например:Result := (Int64(wfad.nFileSizeHigh) shl 32) or wfad.nFileSizeLow;
в первом примереLARGE_INTEGER
обрабатывает это за вас2. Emm… Способ с QuadPart правильный. Способ с
or
определенно неправильный. Почему вы показываете последний фрагмент кода?3. Кроме того, вы должны использовать
UnicodeString
вместоWideString
в D2009 .WideString
является строкой ActiveX / COM и обладает меньшей производительностью, чемUnicodeString
. Что касается поддержки ОС,GetFileAttributesEx
существует со времен XP.4. @MBo Большая часть кода, доступного в Интернете, использует аналогичный код, и вы можете подумать, что я не исследовал, поэтому я показал этот код. например: generacodice.com/en/articolo/119049 /… по этой ссылке показан аналогичный пример, но не работает для больших файлов
5. Спасибо за подсказку по UnicodeString @Remy проверит это
Ответ №1:
Код с записью variant верен.
Но этот код
result:=((amp;wfad.nFileSizeHigh) or (amp;wfad.nFileSizeLow))
просто неверно, результат не может преодолеть 32-разрядную границу
Код по ссылке в комментарии
result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32);
неверно, потому что не учитывает, как компилятор работает с 32 и 64-разрядными значениями. Посмотрите на следующий пример, показывающий, как правильно обращаться с этой ситуацией (для значений d, e):
var
a, b: DWord;
c, d, e: Int64;
wSize:LARGE_INTEGER ;
begin
a := 1;
b := 1;
c := Int64(a) or Int64(b shl 32);
d := Int64(a) or Int64(b) shl 32;
wSize.LowPart := a;
wSize.HighPart := b;
e := wsize.QuadPart;
Caption := Format('$%x $%x $%x', [c, d, e]);
Обратите внимание, что в выражении для c
32-разрядного значения значение сдвигается на 32 бита влево и теряет установленный бит, затем ноль преобразуется в 64-разрядный.
Ответ №2:
Без привязки к тому, как вы получаете размер файла: было бы даже быстрее, если бы вы использовали тип (manual), который существует уже ~ 25 лет, для присвоения размера файла непосредственно результату функции вместо использования промежуточной переменной:
Int64Rec(result).Hi:= wfad.nFileSizeHigh;
Int64Rec(result).Lo:= wfad.nFileSizeLow;
end;
На случай, если это кому-то не очевидно, вот как выглядит компиляция:
Выше: промежуточной переменной w: LARGE_INTEGER
сначала присваиваются две 32-битные части, а затем она сама присваивается результату функции. Стоимость: 10 инструкций.
Выше: запись Int64Rec
используется для приведения результата функции и назначения обеих 32-битных частей напрямую, без необходимости в какой-либо другой переменной. Стоимость: 6 инструкций.
Используемая среда: Delphi 7.0 (Сборка 8.1), версия компилятора 15.0, исполняемый файл Win32, оптимизация кода: включена.
Комментарии:
1. Почему это должно быть быстрее?
2. Это не быстрее.
3. Не идет ни в какое сравнение со стоимостью определения размера файла
4. Вы проверили и пришли к выводу, что в оптимизированном коде вообще есть какая -либо разница? Не похоже, что это какая-то продвинутая, ультрасовременная возможность оптимизации. Это то, что у нас было буквально десятилетиями.
5. На вас лежит ответственность за то, чтобы показать, что это быстрее, а не на нас. У вас есть ответ на это утверждение.