TMemoryStream, судя по коду, не предназначен для работы с кусками размером более 2Gb (для указания размеров везде используется тип Longint). Можно сделать своего потомка от TCustomMemoryStream, он поддерживает максимальные размеры целевой платформы.
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, Pavel Dvorkin, Вы писали:
H>TMemoryStream, судя по коду, не предназначен для работы с кусками размером более 2Gb (для указания размеров везде используется тип Longint). Можно сделать своего потомка от TCustomMemoryStream, он поддерживает максимальные размеры целевой платформы.
Спасибо. Посмотрел исходники, и вот что не понимаю
1.
TCustomMemoryStream = class(TStream)
private
FMemory: Pointer;
FSize, FPosition: NativeInt;
//...procedure TMemoryStream.SetSize(NewSize: Longint);
var
OldPosition: Longint;
begin
OldPosition := FPosition;
SetCapacity(NewSize);
FSize := NewSize;
if OldPosition > NewSize then Seek(0, soFromEnd);
end;
Вроде бы FSize и FPosition объявлены в TCustomMemoryStream как private, а между тем к ним идет обращение из метода наследника TMemoryStream.SetSize. Как такое возможно ? Я попробовал вставить код класса TMemoryStream в свой TLargeMemoryStream, естественно, не компилируется. А как тогда System.Classes компилировалось ?
2.
Судя по
TCustomMemoryStream = class(TStream)
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
function Read(var Buffer; Count: Longint): Longint; override;
даже он не поддерживает чтения больше 2GB. То есть, если я правильно понимаю, смещения в файле могут быть 64-битные, а вот читать можно только не более 2GB.
Здравствуйте, Pavel Dvorkin, Вы писали:
H>>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Вроде бы FSize и FPosition объявлены в TCustomMemoryStream как private, а между тем к ним идет обращение из метода наследника TMemoryStream.SetSize. Как такое возможно ? Я попробовал вставить код класса TMemoryStream в свой TLargeMemoryStream, естественно, не компилируется. А как тогда System.Classes компилировалось ?
А в дельфях хитрющая инкапсуляция. у-у-у! Все классы, объявленные в одном модуле (unit) автоматически как-бы дружественные, и могут свободно друг другу в приват лазить
PD>Что же теперь, писать с нуля ?
Я дельфей после 7-ки не видел, может в новых версиях, поддерживающих 64 бита, какой-нить новый стрим появился. Или переделайте на IStream.
Здравствуйте, Jolly Roger, Вы писали:
JR>А в дельфях хитрющая инкапсуляция. у-у-у! Все классы, объявленные в одном модуле (unit) автоматически как-бы дружественные, и могут свободно друг другу в приват лазить
Спасибо!!!
PD>>Что же теперь, писать с нуля ?
JR> Я дельфей после 7-ки не видел, может в новых версиях, поддерживающих 64 бита, какой-нить новый стрим появился. Или переделайте на IStream.
Тогда уж проще memory mapped files напрямую через uses Windows.
JR>Ну ежель мест, где используется, много, то может проще написать стрим, базирующийся на MMF? ИМХО, и править проще будет, и вероятность ошибок меньше.
Да нет, там просто от стрима берут пойнтер на его буфер, а дальше уже с ним вся работа. В общем, банальность.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD> BE>Читайте блоками и обрабатывайте по частям.
PD> До этого я и сам мог бы догадаться, если бы это проходило. Увы, придется переделывать всю программу.
Зачем переделывать? Ты же сам сказал, что от стрима там только указатель требуется. Делаешь простенькую функцию:
Function GetFileData(Const AFileName : String) : TBytes;
Var
Index : NativeInt;
Count : Integer;
Begin
With TFileStream.Create(AFileName, fmOpenRead Or fmShareDenyWrite) Do
Try
SetLength(Result, Size);
Index := 0;
Repeat
Count := Read(Result[Index], Min(High(Longint), Length(Result) - Index - 1));
Inc(Index, Count);
Until Count < High(Longint);
Finally
Free;
End;
End;
...и задача решена. TBytes приводится к Pointer и всех делов
PD>То, что этот код вызывает ошибку для 3Гб файла в 32-битном режиме , понятно, но почему та же ошибка возникает в x64 ? Можно ли с этим бороться ?
PD>Саму идею загружать 3Гб файл в ОП целиком прошу не обсуждать — не я такое писал.
Не знаю сколько у вас оперативной памяти
Так TMemoryStream – записывает в память
Рекомендую использовать TFileStream – записывает прямо в файлов
Здравствуйте, hattab, Вы писали:
H>Вот этот код 100% работающий:
Сделал отдельный тест — работает. Вставляю код твой без изменения в программу — ERangeCheckError. Мистика.
Что-то с опциями ? Или влияет то, что у меня проект не консольный ? Хотя это уж совсем странно.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Сделал отдельный тест — работает. Вставляю код твой без изменения в программу — ERangeCheckError. Мистика. PD>Что-то с опциями ? Или влияет то, что у меня проект не консольный ? Хотя это уж совсем странно.
ERangeCheckError, ЕМНИП, опциями отключается, в том числе и в свойствах проекта.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD> H>Вот этот код 100% работающий:
PD> Сделал отдельный тест — работает. Вставляю код твой без изменения в программу — ERangeCheckError. Мистика. PD> Что-то с опциями ? Или влияет то, что у меня проект не консольный ? Хотя это уж совсем странно.
Подебажь, что там за значения у индекса. Я проверил свой код (GetFileData) на реальном файле в 3GB с включенными опциями проверки индекса, не на консольном приложении (хотя это значения не имеет) — код рабочий.