Delphi — MemoryStream или FileStream

Я загружаю EXE-файл из Интернета, используя Indy (idHTTP), и я могу использовать поток памяти или поток файлов, чтобы сохранить его на диск, но я действительно не знаю, есть ли между ними какая-либо разница (может быть, в структуре результата файла? ). Я еще не нашел ответа на это.

Где, вот 2 простые функции для имитации того, что я делаю:

Function DownloadMS(FUrl, Dest: String): Boolean;
var
  Http: TIdHTTP;
  Strm: TMemoryStream;
Begin
  Result := False;
  Http := TIdHTTP.Create;
  Strm := TMemoryStream.Create;
  With Http, Strm Do
  Try
    Try
      Get(FUrl, Strm);
      If (Size > 0) Then
      Begin
        Position := 0;
        SaveToFile(Dest);
        Result := True;
      end;
    Except
    end;
  Finally
    Strm.Free;
    Http.Free;
  end;
end;

Function DownloadFS(FUrl, Dest: String): Boolean;
var
  Http: TIdHTTP;
  Strm: TFileStream;
Begin
  Result := False;
  Http := TIdHTTP.Create;
  Strm := TFileStream.Create(Dest, fmCreate);
  With Http, Strm Do
  Try
    Try
      Get(FUrl, Strm);
      Result := (Size > 0);
    Except
    end;
  Finally
    Strm.Free;
    Http.Free;
  end;
end;

Что вы, эксперты, думаете об использовании того или иного типа (memorystream или filestream)? Есть ли разница в структуре EXE-файла при использовании того или иного типа? Какой тип рекомендуется?

Спасибо! Хороших выходных!


person Guybrush    schedule 04.05.2013    source источник
comment
TMemoryStream использует TFileStream для сохранения в файл (для метода SaveToFile), поэтому ответ довольно прост - используйте TFileStream.   -  person TLama    schedule 04.05.2013
comment
Я мог подумать о двух причинах использования TMemoryStream вместо TFileStream. Избегание очистки в файловой системе в случае возникновения исключения и необходимости каких-либо манипуляций перед сохранением в файл.   -  person bummi    schedule 04.05.2013
comment
Ваше необдуманное использование with меня пугает. Я бы рекомендовал вам прекратить это делать.   -  person David Heffernan    schedule 04.05.2013
comment
@bummi, я создаю установщик, который загружает файлы приложений с моего сайта, и я думаю, что вы правы насчет использования потока памяти, потому что соединение может завершиться ошибкой и создать исключение.   -  person Guybrush    schedule 04.05.2013
comment
@DavidHeffernan, спасибо за совет. Я позабочусь в следующий раз.   -  person Guybrush    schedule 04.05.2013
comment
@bummi, я бы сказал, что у подходов есть недостатки, временный беспорядок в файлах с одной стороны и переполнение памяти с другой.   -  person OnTheFly    schedule 04.05.2013


Ответы (2)


Нет никакой разницы между TMemoryStream или TFileStream с точки зрения потока.

Они оба являются потоками и содержат поток байтов, и оба являются производными от TStream.

Вы можете реализовать свою функцию, обобщенную следующим образом

function DownloadToStream( const AUrl : String; ADest : TStream ): Boolean;
var
  LHttp: TIdHTTP;
begin
  LHttp := TIdHTTP.Create;
  try
    LHttp.Get( AUrl, ADest );
    Result := ADest.Size > 0;
  finally
    LHttp.Free;
  end;
end;

и назовите это с помощью TFileStream

var
  LStream : TStream;

begin
  LStream := TFileStream.Create( 'MyFile.exe', fmCreate );
  if DownloadToStream( '', LStream ) then
    ...
end;

или TMemoryStream или любой другой экземпляр потока, который вам нравится

person Sir Rufo    schedule 04.05.2013
comment
Именно так код должен быть рефакторинг. Но я думаю, что вопрос не столько в коде, сколько в дизайне. Вопрос в том, следует ли использовать для этой цели поток памяти или файловый поток. - person David Heffernan; 04.05.2013
comment
@DavidHeffernan Я загружаю EXE-файл из Интернета ... Есть ли разница в структуре EXE-файла при использовании того или иного типа? ОП задается вопросом, будет ли TMemoryStream хранить данные иначе, чем TFileStream: o) - person Sir Rufo; 04.05.2013
comment
Я не прочитал вопрос таким образом, я полагаю, потому что кажется странным, что кто-то может подумать, что содержимое потока изменяется, когда вы сохраняете его на диск, а не в память. Это просто странно! - person David Heffernan; 04.05.2013

Во многих случаях нет смысла размещать промежуточный поток памяти между загрузкой и файлом. Все, что нужно сделать, это потреблять память, потому что вам нужно поместить весь файл в память, прежде чем вы сможете записать его на диск. Использование файлового потока напрямую позволяет избежать этой проблемы.

Основная ситуация, когда возникают проблемы с параметром файлового потока, — это если вы хотите убедиться, что вы успешно загрузили весь файл перед сохранением на диск. Например, если вы перезаписываете предыдущую версию файла, вы можете загрузить ее, проверить хеш-подпись и только потом перезаписать исходный файл. В этом случае вам нужно поместить файл во временное место перед перезаписью. Вы можете использовать поток памяти или файловый поток, используя временное имя файла.

person David Heffernan    schedule 04.05.2013
comment
Да, я создаю установщик, и, возможно, пользователь будет обновлять файлы. Так что я думаю, что я буду использовать MemoryStream, потому что файлы не такие большие (2 или 3 МБ). Спасибо! - person Guybrush; 04.05.2013
comment
@Paruba Вы все еще можете использовать файловый поток, если хотите. Просто используйте временное имя файла. Когда вы довольны загруженным файлом, удалите старый и переименуйте временный файл. - person David Heffernan; 04.05.2013
comment
Использование TFileStream имеет еще одно преимущество — возможность возобновить прерванную загрузку, не начиная с нуля. Если HTTP-сервер поддерживает диапазоны байтов, вы можете настроить TIdHTTP, чтобы сообщить серверу, какую часть удаленного файла следует отправить, а не весь файл. Для небольших файлов это не имеет большого значения, а вот для файлов большего размера может, даже возможность загружать разные разделы одного и того же файла с использованием нескольких потоков одновременно. - person Remy Lebeau; 04.05.2013