6

这是我的场景 - 我有一个 Windows 商店应用程序。我有一个本地文件,以及一个指向 Internet 上文件的链接。有没有办法可以检查这两个文件是否相同,而无需从链接下载文件?

用于获取文件的代码是这样的:

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

}
4

5 回答 5

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在消息本身和它的Content上有多个 Headers 属性。您需要使用适当的属性来检索 ETag 值。

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

编辑 3

终于找到了从 Youtube 获取 ETag 的方法!答案来自“如何使用 YouTube API 获取 YouTube 视频链接的缩略图?

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

gdata.youtube.com另一方面,使用 YouTube 的数据 API 并执行 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();
    ...
}
于 2013-08-08T11:28:33.203 回答
1

You could calculate a hash of the file contents like git does. Use MD5 or similar. Then you only need to check if files have the same hash.

于 2013-08-08T11:24:57.507 回答
1

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

于 2013-08-08T11:27:17.427 回答
0

Directly? No. If the file online is also provided with a Hash, you can get a high probability of successfully checking the equality of the files, though.

于 2013-08-08T11:24:01.193 回答
0

现在随着您的更新,您的代码做了什么很清楚:它从给定的 URL 下载图像并将其存储在给定文件名下的应用程序数据文件夹中。您只想下载任何图像一次。

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

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日期。

然后为了节省带宽,您可以在调用之前使用or标头执行HEAD或条件GET请求,以检查是否有更新的版本可用。if-none-matchif-modified-sinceReadImageFile()

于 2013-08-08T12:28:06.153 回答