2013-08-08 55 views
7

Đây là kịch bản của tôi - Tôi có một ứng dụng cửa sổ cửa sổ. Tôi có một tập tin địa phương, và một liên kết đến một tập tin trên internet. Có cách nào tôi có thể kiểm tra xem hai tệp này có giống nhau không, KHÔNG CÓ tải tệp xuống từ liên kết?So sánh nếu hai tập tin giống nhau trên internet

Các mã được sử dụng để có được các tập tin là thế này:

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

Bạn đang sử dụng dịch vụ lưu trữ nào? Hầu hết các dịch vụ sử dụng băm cho mục đích tương tranh nhưng cách bạn truy xuất băm có thể khác nhau –

+0

các tệp được đề cập là hình thu nhỏ video trên youtube –

+0

Sao chép [Cách tốt nhất để biết hai tệp là giống nhau không?] (Http://stackoverflow.com/questions/714574/best-way-to-tell-if-hai-files-are-the-same). Ngoài ra, câu hỏi của bạn là một oneliner mà không cho bạn hiểu vấn đề (bạn đã nghiên cứu bất kỳ cách nào so sánh các tập tin và tại sao họ không đủ?) Hoặc bạn đã thử bất cứ điều gì. – CodeCaster

Trả lời

7

Giải pháp thông thường là để giữ một hash của file đám mây nơi nào đó, thường là trong siêu dữ liệu của tập tin và so sánh nó với các hash của tệp cục bộ của bạn. Checksums là không phù hợp cho hoạt động này bởi vì họ có một cơ hội rất cao của va chạm (tức là các tập tin khác nhau có cùng checksum).

Hầu hết các dịch vụ lưu trữ (bộ nhớ Azure Blob, Amazon S3, CloudFiles) thực sự sử dụng mã MD5 hoặc SHA của một tệp làm ETag, giá trị được sử dụng để phát hiện các thay đổi đối với tệp cho mục đích lưu vào bộ nhớ cache và đồng thời. Thông thường, thao tác HEAD trên tệp sẽ trả về các tiêu đề và giá trị ETag của nó.

Nếu bạn có tùy chọn chọn thuật toán của riêng mình, hãy chọn SHA256 hoặc cao hơn vì các thuật toán này được tối ưu hóa cao và kích thước khối lớn của chúng có nghĩa là tính toán băm cho tệp lớn nhanh hơn nhiều. SHA256 thực sự nhanh hơn nhiều so với thuật toán MD5 cũ.

Bạn đang sử dụng dịch vụ lưu trữ nào?

EDIT

Nếu bạn chỉ muốn kiểm tra các tập tin để tránh tải chúng một lần nữa, bạn có thể sử dụng ETag trực tiếp. ETag được tạo ra cho chính xác mục đích này. Bạn chỉ cần lưu trữ nó cùng với tệp của bạn khi bạn tải xuống nó lần đầu tiên. Đó là cách proxy và cache biết gửi cho bạn một phiên bản được lưu trong bộ nhớ cache của một bức ảnh thay vì nhấn vào máy chủ đích.

Thực tế, bạn có thể chỉ cần thực hiện GET trên tệp với tiêu đề ETag/If-None-Match. Các proxy trung gian và máy chủ web cuối cùng sẽ trả lại mã trạng thái 304 nếu tệp đích không thay đổi.Điều này sẽ giảm một nửa số yêu cầu bạn cần để tải xuống tất cả hình ảnh trong danh sách của bạn.

Một cách khác là để lưu trữ các giá trị tiêu đề Last Modified cho các tập tin và sử dụng If-Modified-Since tiêu đề trong GET

EDIT 2

Bạn đề cập rằng các ETag là null, mặc dù mã của bạn không hiển thị cách bạn truy xuất mã.

HttpResponseMessage có nhiều thuộc tính Tiêu đề, cả hai on the message itselfContent. Bạn cần sử dụng thuộc tính thích hợp để lấy giá trị ETag.

Bạn cũng có thể kiểm tra bằng cách sử dụng Fiddler để đảm bảo máy chủ thực sự trả về một ETag.

EDIT 3

Cuối cùng tìm ra cách để có được một ETag từ Youtube! Câu trả lời đến từ "How to get thumbnail of YouTube video link using YouTube API?"

Thực hiện HEAD hoặc NHẬN trên hình thu nhỏ của YouTube từ ytimg.com KHÔNG trả lại tiêu đề ETAG hoặc Last-Modified.

Sử dụng API dữ liệu của YouTube và thực hiện GET trên gdata.youtube.com mặt khác, trả về nhiều thông tin về video. Giá trị ETag được bao gồm, mặc dù tôi nghi ngờ nó thay đổi bất cứ khi nào video thay đổi. Điều này có thể được mặc dù, nếu bạn chỉ muốn tải xuống một hình ảnh khi video thay đổi hoặc bạn không muốn tải lại hình ảnh lần nữa.

Code tôi sử dụng là:

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

none, Ý tưởng là người dùng đang duyệt một danh sách các hình ảnh trên internet (danh sách không phải của tôi, cũng không phải nơi họ đang nắm giữ là của tôi) và tôi muốn giới hạn sử dụng băng thông, tức là nếu người dùng đã có hình ảnh này , không tải xuống, chỉ cần tải nó từ bộ nhớ cục bộ. Hình ảnh được đề cập là hình thu nhỏ video trên youtube. –

+0

Đây có thể là trường hợp dễ dàng hơn. Bạn có thể sử dụng HTTP GET với tiêu đề If-XXX để nhận tệp chỉ khi nó đã thay đổi –

+0

Lời khuyên là tốt, nhưng tôi nhận được một ETAG không có trong phản hồi của tôi:/ –

0

trực tiếp? Không. Nếu tập tin trực tuyến cũng được cung cấp với một Hash, bạn có thể nhận được một xác suất cao của việc kiểm tra thành công bình đẳng của các tập tin, mặc dù.

1

Bạn có thể tính giá trị băm của nội dung tệp như git. Sử dụng MD5 hoặc tương tự. Sau đó, bạn chỉ cần kiểm tra xem các tệp có cùng một băm hay không.

+0

Trừ khi tệp trực tuyến đã có sẵn kiểm tra liên kết, Op sẽ vẫn cần phải tải xuống tệp để chạy kiểm tra. – ZombieSheep

+0

Hầu hết các dịch vụ lưu trữ đã sử dụng băm (NOT checksums) cho mục đích này. Thông thường chúng được lưu trữ dưới dạng giá trị ETAG của tệp là –

+0

BTW chiều dài và băm chỉ là tiêu đề, thường được trả về bằng cùng một cuộc gọi. –

1

Nếu bạn muốn thực hiện việc so sánh mà không cần tải xuống và bạn là người đã đặt tệp qua internet. Sau đó, lý tưởng bạn nên đặt một kiểm tra của tệp được tải lên. Sau đó, trước khi tải lên một cái mới, bạn chỉ có thể kiểm tra tổng kiểm tra của tệp cục bộ và tệp trên máy chủ. nếu nó không được tiến hành bình đẳng với việc tải lên khác thì hủy bỏ nó.

-2

Đây là trợ giúp nhỏ. Đối với chính xác cùng một tệp, bạn cần phải kiểm tra MD5 hoặc 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); 
    } 

Bây giờ bạn đã tính toán hashcode của các tệp bây giờ bạn có thể so sánh.

Đối với những người không biết làm thế nào để chuyển đổi liên kết đến dòng:

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

} 
+1

-1 ** liên kết đến một tập tin trên internet ** –

+0

Hãy nhớ rằng đây là một ứng dụng cửa sổ cửa sổ - không có FileStream –

+0

@SriramSakthivel đây chỉ là một ý tưởng để tính toán HashCode. OP có thể có hai liên kết rõ ràng, nếu không câu hỏi đầu tiên của ông sẽ chống lại việc khai thác liên kết Windows Store App –

0

Bây giờ với cập nhật của bạn, nó là loại rõ ràng những gì mã của bạn hiện: nó tải một hình ảnh từ một URL nhất định và lưu trữ nó trong thư mục dữ liệu ứng dụng của bạn dưới sự trao tên tệp. Bạn chỉ muốn tải xuống bất kỳ hình ảnh nào một lần.

Tôi vẫn chưa rõ cách bạn gọi mã này, nhưng giải pháp cho tôi có vẻ như bạn chỉ cần bản dịch "URL thành tên tệp". Vì vậy, trong psuedo:

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

    BitmapImage image; 

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

    return image; 
} 

Điều này không tính đến hình ảnh đã được cập nhật trên máy chủ. Nếu bạn muốn thực hiện điều đó, bạn cần phải lưu siêu dữ liệu trong cuộc gọi DownloadAndSaveImage(), ví dụ: ngày ETag hoặc last-modified được đề cập.

Sau đó, để tiết kiệm băng thông, bạn có thể làm một yêu cầu HEAD hoặc có điều kiện GET với một if-none-match hoặc if-modified-since tiêu đề trước khi cuộc gọi đến ReadImageFile() để kiểm tra xem một phiên bản mới hơn.

Các vấn đề liên quan