![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ошибка в FileSize [Delphi, Windows]
MTsv DN © (2006-12-21 22:55:00)Вот тестовый проект:
program test;
uses KOL;
var
Form, Edit, Button : PControl;
procedure OnClick_( Dummy : Pointer; Sender: PControl);
var
F : File;
Buf : array [0..511] of Byte;
i : integer;
begin
Button.Enabled := false;
Assign(F, 'tmp.tmp');
Rewrite(F, 1);
for i := 0 to 1000 do
BlockWrite(F, Buf, 512);
CloseFile(F);
Button.Enabled := true;
if FileSize('tmp.tmp') < 1000000 then
Edit.Text := 'tmp.tmp';
end;
begin
Form := NewForm(nil, '').SetSize(200, 80);
Form.CenterOnParent;
Edit := NewEditBox(Form, []).SetAlign(caTop);
Button := NewButton(Form, 'Click').SetAlign(caBottom);
Button.OnClick := TOnEvent(MakeMethod(nil, @OnClick_));
Run(Form);
end.
Результат этой строчки в KOL.PAS:
Result := {$IFDEF _D2orD3} FD.nFileSizeLow
{$ELSE} PInt64( @ FD.nFileSizeLow )^ {$ENDIF};
Result := 72339446972273152
Почему бы не вернуться к коду:
function FileSize( const Path: KOLString ) : {$IFDEF _D2orD3} Integer {$ELSE} Int64 {$ENDIF};
var FD : TFindFileData;
HiSize : {$IFDEF _D2orD3} Integer {$ELSE} Int64 {$ENDIF};
begin
Result := 0;
if not Find_First( Path, FD ) then exit;
Result := FD.nFileSizeLow;
{$IFNDEF _D2orD3}
if ((FD.nFileSizeLow and $80000000) <> 0) or
(FD.nFileSizeHigh <> 0) then
begin
HiSize := FD.nFileSizeHigh * MAXDWORD;
Result := HiSize + FD.nFileSizeLow;
end;
{$ENDIF}
Find_Close( FD );
end;
Он также учитывает файлы БОЛЬШИХ РАЗМЕРОВ.
MTsv DN (2006-12-22 22:03:00) [1]2 Galkov ©- снимаю шляпу...
[6] - реально рабочий код... Мой в ауте :( Проверено на файле >10GB
GMax (2006-12-22 20:33:00) [2]вот так делаю я.
это чем-то плохо ?
function GetFileSize64(FN: String): Int64;
var
FD : TWin32FileAttributeData;
begin
Result := -1;
if GetFileAttributesEx(PChar(FN),GetFileExInfoStandard,@FD) then begin
I64(Result).Hi:=FD.nFileSizeHigh;
I64(Result).Lo:=FD.nFileSizeLow;
end;
end;
правда дельфи23 не учитываю, тк не имею
Galkov (2006-12-22 18:31:00) [3]Смеха ради нашел в MSDN еще одну (третью - одну давали Вы, и она там есть, я вторую выше), но уже правильную формулу :)))
nFileSizeHigh
High-order DWORDvalue of the file size, in bytes. This value is zero unless the file size is greater than MAXDWORD. The size of the file is equal to ( nFileSizeHigh* (MAXDWORD+1)) + nFileSizeLow.
nFileSizeLow
Low-order DWORD value of the file size, in bytes.
выделение сохранил из MSDN :)
НО. Нельзя копировать бездумно. Сумма двух dword-ов, это тоже dword, и в данном случае - нулик.
Вы зря не обратили внимания на п.1 из [4]
Если это 5-7 гиг, тоnFileSizeHigh=1, и умножение на MAXDWORD не приводит к переполнению. Суммарная ошибка - всего 1 байт, который можно не заметить.
Для 9 гиг будет ужеnFileSizeHigh=2, а результат произведения на MAXDWORD - 4294967294.
Почувствуйте разницу.
Ибо результатом произведения двух dword-ов будет dword
Но это больше теоретический диспут. У нас все значительно проще, и сложная арифметика не требуется.
MTsv DN (2006-12-22 13:30:00) [4]> Не равен. Не зависимо ни от чьего мнения.
> Арифметика - наука точная.
> Равен может быть только в таком случае:
> nFileSizeHigh * (MAXDWORD+int64(1)) + nFileSizeLow
Совсем плохой стал...сорри...в [5] +1не увидил. Да, здесь Вы правы!!!
Galkov (2006-12-22 13:03:00) [5]
> Причем тут 1.7ГБ???
Тестировать мне нечем, чтобы сказать мог: ПРОВЕРИЛ, И РАБОТАЕТ ПРАВИЛЬНО, ДО ПОСЛЕДНЕГО БАЙТА. Сейчас могу только на других ссылаться.
И больше не причем.
> бОльший размер равен как раз (nFileSizeHigh * MAXDWORD) + nFileSizeLow
Не равен. Не зависимо ни от чьего мнения.
Арифметика - наука точная.
Равен может быть тольков таком случае:
nFileSizeHigh * (MAXDWORD+int64(1)) + nFileSizeLow
MTsv DN (2006-12-22 12:50:00) [6]> 2) Приведенная ф-ла соответствует действительности в случае MAXDWORD=$100000000. Данная MSDN-нарезка из раздела Platform Builder for Microsoft Windows CE 5.0 Не знаю чему там равно MAXDWORD, но в дельфях вроде $FFFFFFFF
MAXDWORD := 4294967295 Причем тут 1.7ГБ???
> Тестировать лично у меня не получалось: мой самый большой
> файл, это на локалке нашел MSDN.rar - всего 1.7Г
Под БОЛЬШИМ ФАЙЛОМ, я имел ввиду размером большим 4ГБ, т.е. максимально разрешенного на FAT32. 1.7ГБ и так правильно в nFileSizeLowполучается, а вот бОльший размер равен как раз (nFileSizeHigh * MAXDWORD) + nFileSizeLow
P.S. Все равно не понимаю, чем Вас код в [0] не устраивает... Я его тестировал на файлах 5 и 7 ГБ... Все правильно возвращает...
Хотя это не принципиально уже...я тему начинал из-за того, что текущая версия FileSize выдает ошибку, а какую реализацию возьмет Владимир неважно, главное, чтобы работало без "косяков"...
Galkov (2006-12-22 12:47:00) [7]Мда... Воды не мало утекло, с тех пор как я разбил стекло :))
В сегодняшнем KOL это уже надо делать так, оказывается:
function FileSize( const Path: KOLString ) : {$IFDEF _D2orD3} Integer {$ELSE} Int64 {$ENDIF};
var FD : TFindFileData;
begin
Result := 0;
if not Find_First( Path, FD ) then exit;
T(Result).L := FD.nFileSizeLow;
{$IFNDEF _D2orD3}T(Result).H := FD.nFileSizeHigh;{$ENDIF}
Find_Close( FD );
end;
Galkov (2006-12-22 12:08:00) [8]btw: В том же MSDN (но чуток в другом под-разделе) есть такое:
nFileSizeHigh
High-order DWORDvalue of the file size, in bytes. This value is zero unless the file size is greater than MAXDWORD. The size of the file is equal to ( nFileSizeHigh* MAXDWORD+1) + nFileSizeLow.
nFileSizeLow
Low-order DWORDvalue of the file size, in bytes.
Думается, что здесь адекватнее говорить не о потерянной паре скобок, а о заборе
У меня MSDN April 2005 :)))))
Galkov (2006-12-22 11:22:00) [9]1) Откуда известно, что призведение двух dword-ов будет int64 ??? Народ против таких приколов всякие MulDiv-ы изобретал....
2) Приведенная ф-ла соответствует действительности в случае MAXDWORD=$100000000. Данная MSDN-нарезка из раздела Platform Builder for Microsoft Windows CE 5.0
Не знаю чему там равно MAXDWORD, но в дельфях вроде $FFFFFFFF
3) Мало ли чего на заборе пишут....
Тестировать лично у меня не получалось: мой самый большой файл, это на локалке нашел MSDN.rar - всего 1.7Г
Но когда народ спрашивал, я им выкинул такой fix, и получил радостные сообщения о соответствии показаний с другими ф.менеджерами
function FileSize( const Path : String ) : Int64;
type T = record L,H:DWORD end;
var FD : TWin32FindData;
FH : THandle;
begin
FH := FindFirstFile( PChar( Path ), FD );
Result := 0;
if FH = INVALID_HANDLE_VALUE then exit;
T(Result).L := FD.nFileSizeLow;
T(Result).H := FD.nFileSizeHigh;
FindClose( FH );
end;
MTsv DN (2006-12-22 10:00:00) [10]> Учитывает. Только правильно ли :)))
Понял что намек, но не понял на что :)
Вот из MSDN про это:
nFileSizeHigh
Specifies the high-order DWORD value of the file size, in bytes. This value is zero unless the file size is greater than MAXDWORD. The size of the file is equal to (nFileSizeHigh * MAXDWORD) + nFileSizeLow.
nFileSizeLow
Specifies the low-order DWORD value of the file size, in bytes.
А на две операции разбил, т.к. когда тестил получалось типа косяка в [0]
Galkov (2006-12-22 09:02:00) [11]
> Он также учитывает файлы БОЛЬШИХ РАЗМЕРОВ.
Учитывает. Только правильно ли :)))
Galkov (2006-12-22 00:21:00) [12]Конечно бага... У Билла тоже - ума палата. Это надо же было старшее слово раньше поставить...
Хитрые умножения против 2-х mov-ов это перебор, конечно...
Что-нибудь такого типа надо:
type T = record L,H:DWORD end;
..........
T(Result).L := FD.nFileSizeLow;
T(Result).H := FD.nFileSizeHigh;