2013-05-04 25 views
6

Sto scaricando un file EXE da internet usando Indy (idHTTP), e posso usare memorystream o filestream per salvarlo su disco, ma davvero non so se c'è qualche differenza tra loro (forse nella struttura dei risultati del file?). Non ho ancora trovato una risposta per questo.Delphi - MemoryStream o FileStream

Dove, qui ci sono 2 funzioni semplici per simulare quello che sto facendo:

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; 

Quello che gli esperti pensare di utilizzare uno o l'altro tipo (MemoryStream o FileStream)? C'è qualche differenza nella struttura del file EXE quando si utilizza uno o altro tipo? Che tipo è raccomandato?

Grazie! Passa un bel weekend!

+4

Il 'TMemoryStream' utilizza internamente' TFileStream' per il salvataggio su file (per il metodo 'SaveToFile'), quindi la risposta è piuttosto semplice - usa' TFileStream'. – TLama

+0

Potrei pensare a 2 motivi per l'utilizzo di TMemoryStream invece di TFileStream. Evitare una pulizia del filesystem in caso di un'eccezione e la necessità di alcune manipolazioni prima di salvarlo in un file. – bummi

+6

Il tuo uso sfrenato di 'with' mi fa paura. Ti consiglio di smettere di farlo. –

risposta

5

Nessuna differenza tra TMemoryStream o TFileStream dal punto di vista dello stream.

Sono entrambi flussi e contengono un flusso di byte e sono entrambi derivati ​​da TStream.

è possibile implementare la funzione generalizzata come questo

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; 

e chiamarlo con un TFileStream

var 
    LStream : TStream; 

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

o TMemoryStream o qualunque istanza del flusso gradite

+0

Questo è il modo in cui il codice dovrebbe essere rielaborato. Ma penso che la questione non sia tanto sul codice, quanto sul design. Il flusso di memoria o il flusso di file dovrebbero essere usati per questo scopo sembra essere la domanda. –

+1

@DavidHeffernan "Sto scaricando un ** file EXE ** da Internet ... C'è qualche differenza nella struttura del ** file EXE ** quando si utilizza uno o l'altro tipo?" OP si chiede se 'TMemoryStream' memorizzerà i dati diversi da' TFileStream' farebbe: o) –

+0

Non ho letto la domanda in questo modo, suppongo perché sembra strano che qualcuno possa pensare che il contenuto di un flusso sia cambiato quando lo si archivia su disco anziché su memoria. È strano! –

1

In molti casi non ci sarà alcun punto nel mettere un flusso di memoria intermedio tra il download e il file. Tutto ciò che verrà fatto è consumare memoria perché devi mettere l'intero file in memoria prima di poterlo inserire sul disco. L'utilizzo di un flusso di file evita direttamente tale problema.

La situazione principale in cui l'opzione del flusso di file presenta problemi è se si vuole essere sicuri di aver scaricato l'intero file con successo prima di salvare su disco. Ad esempio, se si sta sovrascrivendo una versione precedente di un file, è possibile scaricarlo, controllare una firma hash e solo successivamente sovrascrivere il file originale. In tale scenario è necessario mettere il file in una posizione temporanea prima di sovrascrivere. È possibile utilizzare un flusso di memoria oppure è possibile utilizzare un flusso di file utilizzando un nome file temporaneo.

+0

Sì, sto creando un programma di installazione e forse l'utente aggiornerà i file. Quindi penso che userò MemoryStream, perché i file non sono così grandi (2 o 3 MB). Grazie! – Guybrush

+0

@Paruba È ancora possibile utilizzare un flusso di file, se lo si desidera. Basta usare un nome di file temporaneo. Quando sei felice del file scaricato, cancella il vecchio e rinomina il file temporaneo. –

+9

L'uso di un 'TFileStream' ha un altro vantaggio: la possibilità di riprendere un download interrotto senza ricominciare da capo.Se il server HTTP supporta gli intervalli di byte, è possibile configurare 'TIdHTTP' per comunicare al server quale parte del file remoto inviare, invece dell'intero file. Per i file di piccole dimensioni, non importa molto, ma per i file più grandi è possibile, anche la possibilità di scaricare sezioni diverse dello stesso file utilizzando più thread contemporaneamente. –