2013-08-08 12 views
7

Ecco il mio scenario: ho un'app di Windows Store. Ho un file locale e un link a un file su internet. C'è un modo per verificare se questi due file sono uguali, WITHOUT scaricando il file dal collegamento?Confronta se due file sono uguali su Internet

Il codice utilizzato per ottenere il file è questo:

private static async void SetImage(PlaylistItem song, string source, string imageName) 
{ 

    HttpClient client = new HttpClient(); 

    HttpResponseMessage message = await client.GetAsync(source); 

    StorageFolder myfolder = Windows.Storage.ApplicationData.Current.LocalFolder; 
    StorageFile sampleFile = await myfolder.CreateFileAsync(imageName, CreationCollisionOption.ReplaceExisting); 
    byte[] byteArrayFile = await message.Content.ReadAsByteArrayAsync(); 

    await FileIO.WriteBytesAsync(sampleFile, byteArrayFile); 

    song.Image = new BitmapImage(new Uri(sampleFile.Path)); 

} 
+0

Quale servizio di archiviazione stai utilizzando? La maggior parte dei servizi utilizza gli hash per scopi di concorrenza, ma il modo in cui li recuperi può variare –

+0

i file in questione sono miniature dei video di YouTube –

+0

Duplicato di [Il modo migliore per sapere se due file sono uguali?] (Http://stackoverflow.com/questions/714.574/best-way-to-dire-se-due-files-are-the-same). Inoltre, la tua domanda è una oneliner che non ti mostra di aver compreso il problema (hai cercato dei modi per confrontare i file e perché non erano sufficienti?) O di aver provato qualcosa. – CodeCaster

risposta

7

La soluzione più comune è quello di mantenere un hash del file nuvola da qualche parte, di solito nei metadati del file e confrontarlo con l'hash del tuo file locale. I checksum non sono adatti a questa operazione perché hanno un'alta probabilità di collisione (ovvero file diversi con lo stesso checksum).

La maggior parte dei servizi di archiviazione (archiviazione BLOB di Azure, Amazon S3, CloudFiles) utilizza effettivamente l'hash MD5 o SHA di un file come ETag, il valore utilizzato per rilevare le modifiche a un file per scopi di caching e simultaneità. In genere, un'operazione HEAD sul file restituirà le intestazioni e il valore ETag.

Se si ha la possibilità di scegliere il proprio algoritmo, scegliere SHA256 o superiore poiché questi algoritmi sono altamente ottimizzati e le loro dimensioni di blocco grandi significano che il calcolo degli hash per i file di grandi dimensioni è molto più veloce. SHA256 è in realtà molto più veloce dell'algoritmo MD5 precedente.

Quale servizio di archiviazione stai utilizzando?

EDIT

Se si desidera solo per controllare i file per evitare di scaricare di nuovo, è possibile utilizzare l'ETag direttamente. ETag è stato creato esattamente per questo scopo. Devi solo memorizzarlo insieme al tuo file quando lo scarichi la prima volta. È così che i proxy e le cache sanno di inviarti una versione cache di una foto invece di colpire il server di destinazione.

In effetti, probabilmente è sufficiente eseguire un GET sul file con le intestazioni ETag/If-None-Match. I proxy intermedi e il server Web finale restituiranno un codice di stato 304 se il file di destinazione non è stato modificato.Questo dimezza il numero di richieste necessarie per scaricare tutte le immagini nel tuo elenco.

Un'alternativa è quella di memorizzare il valore Last-Modified per il file e utilizzare il If-Modified-Since in GET

EDIT 2

Lei ha accennato che l'intestazione ETag è nullo, sebbene il tuo codice non mostri come lo recuperi.

HttpResponseMessage ha più proprietà di intestazioni, sia on the message itself e sia Content. È necessario utilizzare la proprietà corretta per recuperare il valore ETag.

È inoltre possibile controllare utilizzando Fiddler per assicurarsi che il server restituisca effettivamente un ETag.

EDIT 3

finalmente trovato un modo per ottenere un ETag da Youtube! La risposta viene da "How to get thumbnail of YouTube video link using YouTube API?"

Fare un HEAD o GET su una miniatura di YouTube da ytimg.com NON restituisce le intestazioni ETag o Last-Modified.

L'utilizzo dell'API dati di YouTube e l'esecuzione di un GET su gdata.youtube.com d'altra parte restituisce una grande quantità di informazioni sul video. È incluso un valore ETag, anche se sospetto che cambi ogni volta che il video cambia. Questo può essere OK, tuttavia, se si desidera scaricare un'immagine solo quando il video cambia, o se non si desidera scaricare nuovamente l'immagine.

Il codice che ho usato era:

var url = "http://gdata.youtube.com/feeds/api/videos/npvJ9FTgZbM?v=2&prettyprint=true&alt=json"; 

using(var client = new HttpClient()) 
{ 
    var response = await client.GetAsync(url); 
    var etag1 = response.Headers.ETag; 
    var content = await response.Content.ReadAsStringAsync(); 
    ... 
} 
+0

nessuno, L'idea è che l'utente sta navigando un elenco di immagini su Internet (l'elenco non è mia, né il luogo in cui sono detenuti è mio) e voglio limitare l'utilizzo della larghezza di banda, cioè se l'utente ha già questa immagine , non scaricarlo, basta caricarlo dalla memoria locale. Le immagini in questione sono miniature dei video di youtube. –

+0

Questo potrebbe essere un caso più semplice. È possibile utilizzare HTTP GET con le intestazioni If-XXX per ottenere un file solo se è cambiato –

+0

Il consiglio è buono, ma ottengo un ETag nulla nella mia risposta:/ –

0

direttamente? No. Se il file online è dotato anche di un hash, è comunque possibile ottenere un'alta probabilità di controllare correttamente l'uguaglianza dei file.

1

È possibile calcolare un hash del contenuto del file come git fa. Usa MD5 o simile. Quindi devi solo controllare se i file hanno lo stesso hash.

+0

A meno che il file online non abbia già un checksum associato, Op dovrebbe comunque scaricare il file per eseguire il controllo. – ZombieSheep

+0

La maggior parte dei servizi di archiviazione utilizza già hash (NON checksum) per questo scopo. Generalmente vengono memorizzati come valore ETag del file –

+0

BTW la lunghezza e l'hash sono solo intestazioni, in genere restituite dalla stessa chiamata. –

1

Se si desidera effettuare un confronto senza scaricare e si è colui che ha inserito il file su Internet. Quindi idealmente si dovrebbe inserire un checksum del file caricato. Quindi, prima di caricarne uno nuovo, è sufficiente il controllare il checksum del file locale e quello sul server. se non è uguale procedi con l'upload altrimenti cancellalo.

-2

Ecco il piccolo aiuto. Per esattamente stesso file è necessario controllare MD5 o Hashchecks

public static string CalcHashCode(string filename) 
    { 
     FileStream stream = new FileStream(
      filename, 
      System.IO.FileMode.Open, 
      System.IO.FileAccess.Read, 
      System.IO.FileShare.ReadWrite); 

     try 
     { 
      return CalcHashCode(stream); 
     } 
     finally 
     { 
      stream.Close(); 
     } 
    } 

    public static string CalcHashCode(FileStream file) 
    { 
     MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider(); 
     Byte[] hash = md5Provider.ComputeHash(file); 
     return Convert.ToBase64String(hash); 
    } 

Ora avete calcolato il codice hash dei file ora si può confrontare.

Per coloro che non sapere come convertire collegamento per lo streaming:

WebRequest req = HttpWebRequest.Create("url here"); 
using (Stream stream = req.GetResponse().GetResponseStream()) 
{ 

} 
+1

-1 ** collegamento a un file su Internet ** –

+0

Si prega di tenere presente che questa è un'app di Windows Store - no FileStream –

+0

@SriramSakthivel questa è solo un'idea per calcolare l'HashCode. OP potrebbe avere i due collegamenti ovviamente, altrimenti la sua prima domanda sarà contro l'estrazione del collegamento App Store di Windows –

0

Ora con l'aggiornamento, è una specie di chiaro ciò che il codice fa: si scarica un'immagine da un determinato URL e lo memorizza nella cartella di dati delle applicazioni sotto la data nome del file. Vuoi scaricare qualsiasi immagine solo una volta.

Non mi è ancora chiaro come si chiami questo codice, ma la soluzione per me sembra che sia sufficiente una traduzione "URL per nome file". Quindi, in psuedo:

BitmapImage GetImage(string sourceURL) 
{ 
    string filename = GetFilenameForURL(sourceURL); 

    BitmapImage image; 

    if (!FileExists(filename)) 
    { 
     image = DownloadAndSaveImage(sourceURL, filename); 
    } 
    else   
    {  
     image = ReadImageFile(filename); 
    } 

    return image; 
} 

Questo non tiene conto delle immagini che sono state aggiornate sul server. Se si desidera farlo, è necessario salvare i metadati nella chiamata DownloadAndSaveImage(), ad esempio la citata data ETag o last-modified.

Poi, per risparmiare larghezza di banda, si può fare una richiesta HEAD o condizionale GET con un'intestazione if-none-match o if-modified-since prima della chiamata a ReadImageFile() per verificare se una versione più recente è disponibile.

Problemi correlati