Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > I7zOutArchive (sevenzip.pas) и работа с потоковыми


Автор: lollollollol 12.3.2013, 15:52
Доброго времени суток!

У меня такая проблема:

Код

var
...
OutArchive: I7zOutArchive;
begin
...
        OutArchive := CreateOutArchive(CLSID_CFormatZip);
        try
          Stream.Position:=0;
          Stream.SetMemPointer(Pointer(@GenA.files),size);
          Stream.SetPointer(Pointer(@GenA.files),size);
OutArchive.AddStream(Stream[id],soReference,faReadOnly,DateTimeToFileTime(Now),DateTimeToFileTime(Now),name,False,True);

          SetCompressionLevel(OutArchive, 4);
          SetCompressionMethod(OutArchive, mzDeflate);
          Stream.Position:=0;
          Stream.SetMemPointer(Pointer(@GenA.files),size);
          Stream.SetPointer(Pointer(@GenA.files),size);
          OutArchive.SaveToStream(Stream);
          size:=Stream.GetSize;
          OutArchive.SaveToFile('C:\12225.zip');

Мне нужно запаковать в зип арзив один файл, который находится в масиве байт (array of byte)
Вначале я устанавливаю указать Tstream на начало массива в котором содержится файл,
затем пытаюсь загрузить поток в OutArchive, запаковать, и сохоанить для проверки результата.

Но проблема в том что такой вариант пакует только первые 170-180 байт.
Если загрузить файл, (OutArchive.AddFile) то всё работает отлично.


Помогите запаковать файл из потока, не загружая его с диска


Спасибо

Добавлено через 10 минут и 33 секунды
Попытался загрузить файл в поток Stream.LoadFromFile, но проблема осталась прежней. 
Вероятно я неправильно пытаюсь передать потоковые данные. Смущает что нигде не требуется указать длину данных. 

Автор: lollollollol 12.3.2013, 16:18
Или может быть возможно загрузить пустой файл, а потом записать новый буфер, и указать нвый размер? я не могу найти подходящих методов

Автор: lollollollol 12.3.2013, 18:03
Кто работал, прошу помочь.

Моя цель: Имеется массив байт-это файл.
Данный файл нужно запаковать в архив. В архиве этот файл должен быть один, с заданым мною именем. Но сам архив должен быть тоже в виде Tstream или простого массива байт.

То есть запаковать файл который находится в памяти, и оставить архив в памяти, без сохранения на диск.

Приведённый выше код сделал бы это, еслибы получилось агрузить файл не с диска, и из потока.

Если кто может помочь, очень прошу.


Для решения возможны варианты сторонных dll, ругих модулей или компонентов, но главное условие - работа без сохранения на диск, возможность запаковать один файл с указаным именем в архив.

Автор: Чучмек 13.3.2013, 09:58
И в чем проблема?
Код

type
 TMMStream=class(TCustomMemoryStream);
var
 i7zOut:I7zOutArchive;
 ms:TMMStream;
begin
ms:=TMMStream.Create;
ms.SetPointer(m,length(m)*sizeOf(m[0])); 
i7zOut:=CreateOutArchive(CLSID_CFormatZip);
//i7zOut.SetPropertie
i7zOut.AddStream(ms,...);
i7zOut.SaveToFile(filename);
ms.free;
end;



Автор: lollollollol 13.3.2013, 15:23
Поменял тип TMemoryStream на TCustomMemoryStream, теперь архив создаётся, записыватся в файл.
А вот при попытке сделать OutArchive.SaveToStream(Stream[id]);  получаю ошибку.

Автор: lollollollol 13.3.2013, 15:39
Если создать две разные перемнные, то всё ок. Но я хотел сохранить снова в ту, с которой брал. Чтобы не создавать много копий в памяти.

И ещё момент, компилятор ругается
[Warning] Unit1.pas(2161): Constructing instance of 'TMMStream' containing abstract method 'TStream.Write'

Автор: Чучмек 13.3.2013, 17:10
Цитата(lollollollol @  13.3.2013,  15:23 Найти цитируемый пост)
А вот при попытке сделать OutArchive.SaveToStream(Stream[id]);  получаю ошибку. 

Цитата(lollollollol @  13.3.2013,  15:39 Найти цитируемый пост)
[Warning] Unit1.pas(2161): Constructing instance of 'TMMStream' containing abstract method 'TStream.Write'

Сопоставь одно с другим.

Автор: Чучмек 13.3.2013, 17:35
Переопредели в TMMStream абстрактный метод  Write
Код

type
 TMMStream=class(TCustomMemoryStream)
   function Write(const Buffer; Count: Longint): Longint; override;
  end;
...
{ TMMStream }

function TMMStream.Write(const Buffer; Count: Integer): Longint;
begin
move(buffer,(PAnsiChar(Memory)+Position)^,count);
Position:=Position+count;
result:=count;
end;

Только учти, что если сжатый файл больше несжатого (Position+count>length(m)*sizeOf(m[0]) получишь AV

Автор: lollollollol 13.3.2013, 19:37
Stream[id] Эт просто у меня массив переменных, array of TMemoryStream

В каких случаях сжатый может быть больше несжатого? Сейчас он стабильно меньше на 15-30%


Спасибо за помощь, всё получилось!  хотел поставить тебе плюс, но нельзя. Если кто поставит за меня, буду благодарен:)

Автор: Чучмек 13.3.2013, 19:46
1. Сжимается маленький файл 
2. Файл содержит уже сжатую информацию. mp3 например.

Добавлено через 3 минуты и 32 секунды
Заполни массив случайными числами.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)