Ho un inputStream
che voglio usare per calcolare un hash e salvare il file su disco. Mi piacerebbe sapere come farlo in modo efficiente. Devo utilizzare qualche attività per farlo contemporaneamente, dovrei duplicare lo stream passare a due flussi, uno per il metodo saveFile
e uno per il metodo computeHash
, o dovrei fare qualcos'altro?Calcolare l'hash durante il salvataggio di un file?
risposta
È necessario inserire i byte del flusso in un byte[]
per cancellarli.
Puoi anche passare uno stream. Quali sarebbero i vantaggi della conversione del flusso in un byte []? – Dave
Io, per qualche ragione, non ho visto quel sovraccarico. Mai. Io andrò a dire 10 "Hail Bills Gates" "in penance. – bluevector
@Dave Non c'è alcun vantaggio. Sia la forma che accetta un 'byte []' che un 'Stream' stanno bloccando e si aspettano l'intero dato in un colpo solo. Con i thread e uno speciale 'Stream' ... ma questo aggiunge solo più problemi allora risolve ... –
Che dire di utilizzare un algoritmo di hash che funziona a livello di blocco? È possibile aggiungere il blocco all'hash (utilizzando TransformBlock) e successivamente scrivere il blocco sul blocco foreach del file nel flusso.
testato colpo di massima:
using System.IO;
using System.Security.Cryptography;
...
public byte[] HashedFileWrite(string filename, Stream input)
{
var hash_algorithm = MD5.Create();
using(var file = File.OpenWrite(filename))
{
byte[] buffer = new byte[4096];
int read = 0;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
hash_algorithm.TransformBlock(buffer, 0, read, null, 0);
file.Write(buffer, 0, read);
}
hash_algorithm.TransformFinalBlock(buffer, 0, read);
}
return hash_algorithm.Hash;
}
Non sono un grande fan dell'elaborazione manuale dei blocchi, ma dovrebbe funzionare. (Penso che CryptoStream sia un approccio più semplice che si riduce ad essere un bel wrapper.) –
Concordato. Generalmente li evito come la peste (grazie a Dio per il recente metodo Stream.CopyTo) ... Penso che questo sia il modo migliore per risolvere il problema. Inoltre, una seconda lettura mi fa pensare che ho un bug in cui il blocco finale è stato sottoposto a hash due volte ... Per essere un MD5 accurato, dovresti rilevare la EOS e gestire l'ultimo blocco in modo diverso. –
potrebbe non essere l'opzione migliore, ma vorrei scegliere di andare per Stream
discendente/involucro, quello che sarebbe pass-through per una realtà scrivere il file il disco.
Quindi:
- derivare da
Stream
- dispone di un membro, come
Stream _inner;
che sarà il flusso di destinazione di scrivere - attuare
Write()
e tutte le cose relative - in
Write()
hash i blocchi di dati e chiamare_inner.Write()
Esempio di utilizzo
Stream s = File.Open("infile.dat");
Stream out = File.Create("outfile.dat");
HashWrapStream hasher = new HashWrapStream(out);
byte[] buffer=new byte[1024];
int read = 0;
while ((read=s.Read(buffer)!=0)
{
hasher.Write(buffer);
}
long hash=hasher.GetComputedHash(); // get actual hash
hasher.Dispose();
s.Dispose();
Ecco la mia soluzione, scrive una serie di struct (la variabile zecche) come file CSV (utilizzando il pacchetto di NuGet CsvHelper) e quindi crea un hash per scopi di checksum utilizzando il suffisso. sha256
Lo faccio scrivendo il csv su un memoryStream, quindi scrivendo il flusso di memoria su disco, quindi passando il memorystream all'algo hash.
Questa soluzione consente di mantenere l'intero file come un memorandum. Va bene per tutto tranne i file multi-gigabyte che ti farebbero uscire dalla ram. Se dovessi farlo di nuovo, probabilmente tenterei di usare l'approccio CryptoStream, ma questo è abbastanza buono per i miei scopi prevedibili.
Ho verificato tramite uno strumento di terze parti che gli hash sono validi.
Ecco il codice:
//var ticks = **some_array_you_want_to_write_as_csv**
using (var memoryStream = new System.IO.MemoryStream())
{
using (var textWriter = new System.IO.StreamWriter(memoryStream))
{
using (var csv = new CsvHelper.CsvWriter(textWriter))
{
csv.Configuration.DetectColumnCountChanges = true; //error checking
csv.Configuration.RegisterClassMap<TickDataClassMap>();
csv.WriteRecords(ticks);
textWriter.Flush();
//write to disk
using (var fileStream = new System.IO.FileStream(targetFileName, System.IO.FileMode.Create))
{
memoryStream.Position = 0;
memoryStream.CopyTo(fileStream);
}
//write sha256 hash, ensuring that the file was properly written
using (var sha256 = System.Security.Cryptography.SHA256.Create())
{
memoryStream.Position = 0;
var hash = sha256.ComputeHash(memoryStream);
using (var reader = System.IO.File.OpenRead(targetFileName))
{
System.IO.File.WriteAllText(targetFileName + ".sha256", hash.ConvertByteArrayToHexString());
}
}
}
}
}
Questo metodo copia e hash con i flussi concatenati.
private static byte[] CopyAndHash(string source, string target, Action<double> progress, Func<bool> isCanceled)
{
using(var sha512 = SHA512.Create())
using (var targetStream = File.OpenWrite(target))
using (var cryptoStream = new CryptoStream(targetStream, sha512, CryptoStreamMode.Write))
using (var sourceStream = File.OpenRead(source))
{
byte[] buffer = new byte[81920];
int read;
while ((read = sourceStream.Read(buffer, 0, buffer.Length)) > 0 && !isCanceled())
{
cryptoStream.Write(buffer, 0, read);
progress?.Invoke((double) sourceStream.Length/sourceStream.Position * 100);
}
File.SetAttributes(target, File.GetAttributes(source));
return sha512.Hash;
}
}
campione completa vedere https://gist.github.com/dhcgn/da1637277d9456db9523a96a0a34da78
- 1. UnauthorizedAccessException durante il salvataggio di un file
- 2. set di estensione file iniziale durante il salvataggio del file
- 3. Disabilitare il codice di riformattazione durante il salvataggio dei file
- 4. Valore errato durante il salvataggio di enum
- 5. rimozione doctype durante il salvataggio di domdocument
- 6. Flask: IOError durante il salvataggio dei file caricati
- 7. L'evidenziazione della sintassi scompare casualmente durante il salvataggio del file
- 8. Salvataggio di un file temporaneo
- 9. Come funziona after_save lavoro durante il salvataggio di un oggetto
- 10. errore parquet durante il salvataggio da Spark
- 11. Sessione persa durante il salvataggio dei cookie
- 12. Rails EOFError (fine del file raggiunto) durante il salvataggio di un utente utente
- 13. Problema durante il salvataggio di un file SVG generato da Raphael JS in una tela
- 14. Errore durante il salvataggio dell'area di lavoro in ColdFusion Builder
- 15. estensione mancante durante il salvataggio di un'immagine da tela
- 16. UIDocument & NSFileWrapper - NSFastEnumerationMutationHandler durante la modifica del file wrapper durante un salvataggio
- 17. MySQL utf8mb4, Errori durante il salvataggio di Emojis
- 18. Java: Salvataggio di StreamResult in un file
- 19. Salvataggio di CGImageRef in un file png?
- 20. apache poi: salvataggio di un file in un file
- 21. AFNetworking - salvataggio di un file scaricato
- 22. Salvataggio automatico di un file SVG?
- 23. StaleStateException durante il salvataggio di entità con relazioni complesse
- 24. Lo sfondo diventa nero durante il salvataggio di Bitmap - C#
- 25. Smalltalk - raccolta è vuoto errore durante il salvataggio
- 26. Evitare la perdita di dati dovuta all'interruzione durante il salvataggio dei file su Android?
- 27. Salvataggio di un NSArray
- 28. Calcolare l'hash durante la scrittura nello stream
- 29. Perché il post_save viene sollevato due volte durante il salvataggio di un modello Django?
- 30. Calcolare il tempo differenza tra due file
ho fatto una domanda simile di recente: http://stackoverflow.com/questions/10985282/generate-running-hash-or-checksum-in-c (le risposte sono probabilmente applicabile qui a causa dei vincoli), ho assunto "hash" per indicare MD5, SHAx, ecc. –
Ho usato SHA256Cng e posso anche salvare il file.La mia domanda è più di fare entrambe le cose contemporaneamente (usando task/future) o sequenzialmente (la lettura di un filestream sposta il puntatore interno, quindi posso resettare il puntatore a zero o duplicare il puntatore). Non so quale sia il migliore e come farlo. – Dave
* riflette sulla lettura della domanda collegata * (Prendi in considerazione anche uno "stream splitter", che potrebbe essere usato per ridurre potenzialmente del lavoro manuale di copia tra due flussi di output.) –