比较两个文件在互联网上是否相同

时间:2013-08-08 11:22:06

标签: c# file http-headers youtube-api windows-store-apps

这是我的方案 - 我有一个Windows商店应用程序。我有一个本地文件,以及一个指向互联网上文​​件的链接。有没有办法可以检查这两个文件是否相同,没有从链接下载文件?

用于获取文件的代码是:

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));

}

5 个答案:

答案 0 :(得分:7)

通常的解决方案是在某处保留云文件的哈希值,通常在文件的元数据中,并将其与本地文件的哈希值进行比较。校验和不适用于此操作,因为它们具有很高的冲突机会(即具有相同校验和的不同文件)。

大多数存储服务(Azure Blob存储,Amazon S3,CloudFiles)实际上使用文件的MD5或SHA哈希作为其ETag,该值用于检测文件的更改以进行缓存和并发。通常,对文件的HEAD操作将返回其标题和ETag值。

如果您可以选择自己选择算法,请选择SHA256或更高版本,因为这些算法经过高度优化,其大块大小意味着计算大文件的哈希速度要快得多。 SHA256实际上比旧的MD5算法快得多。

您使用的是哪种存储服务?

修改

如果您只想检查文件以避免再次下载,可以直接使用ETag。 ETag就是为了这个目的而创建的。第一次下载时,您只需将其与文件一起存储即可。这就是代理和缓存知道向您发送图片的缓存版本而不是命中目标服务器的方式。

实际上,您可以使用ETag / If-None-Match标头对文件执行GET。如果目标文件未更改,则中间代理和最终Web服务器将返回304状态代码。这样可以减少下载列表中所有图像所需的请求数量。

另一种方法是存储文件的Last-Modified标头值,并在GET中使用If-Modified-Since标头

编辑2

您提到ETag标头为空,尽管您的代码未显示如何检索它。

HttpResponseMessage具有多个标头属性,on the message itself及其Content。您需要使用适当的属性来检索ETag值。

您还可以使用Fiddler进行检查,以确保服务器确实返回ETag。

编辑3

终于找到了从Youtube获得ETag的方法!答案来自“How to get thumbnail of YouTube video link using YouTube API?

ytimg.com的YouTube缩略图上执行HEAD或GET不会返回ETag或Last-Modified标头。

另一方面,使用YouTube的数据API并在gdata.youtube.com上进行GET,会返回有关视频的大量信息。包含ETag值,但我怀疑它会在视频发生变化时发生变化。这可能没问题,如果您只想在视频发生变化时下载图像,或者您不想再次下载图像。

我使用的代码是:

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();
    ...
}

答案 1 :(得分:1)

您可以像git一样计算文件内容的哈希值。使用MD5或类似的。然后,您只需要检查文件是否具有相同的哈希值。

答案 2 :(得分:1)

如果您想在不下载的情况下进行比较,那么您就是将该文件放在互联网上的人。理想情况下,您应放置已上传文件的校验和。然后在上传新文件之前,您只需检查本地文件的校验和和服务器上的文件。如果不相等则继续上传,否则取消它。

答案 3 :(得分:0)

直接?不可以。如果在线文件也提供了哈希,那么你很有可能成功检查文件是否相等。

答案 4 :(得分:0)

现在有了您的更新,您可以清楚地看到代码的作用:它从给定的URL下载图像并将其存储在给定文件名下的应用程序数据文件夹中。您只想下载任何图像一次。

我仍然不清楚你如何调用这段代码,但对我来说解决方案看起来只需要一个“URL to filename”翻译。所以,在psuedo中:

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

    BitmapImage image;

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

    return image;
}

这不考虑已在服务器上更新的图像。如果您想这样做,则需要在DownloadAndSaveImage()调用中保存元数据,例如提及的ETaglast-modified日期。

然后为了节省带宽,您可以在调用HEAD之前使用GETif-none-match标头执行if-modified-since或条件ReadImageFile()请求如果有更新的版本。