我有一个用Xamarin.iOS编写的应用程序,导致文件在下载到应用程序后被破坏。
我通过下载应用程序中的文件来比较校验和,然后将下载的文件上传到dropbox。然后我将dropbox文件的校验和与服务器上的原始文件进行比较。
通常,校验和匹配。偶尔,校验和不匹配。这些文件实际上是视频,导致视频无法播放。
如何下载(使用HttpWebRequest
)偶尔会导致文件损坏,但继续成功下载?
public class DownloadService : IDownloadService
{
private const int BufferSize = 1024*1024;
/// <summary>
/// Download a remote file to a local location.
/// </summary>
/// <param name="url">The url of the file to download.</param>
/// <param name="localPath">The local path to save the file.</param>
/// <param name="progress">The progress off the download (percentage|bytesread|totalbytes).</param>
/// <param name="cancel">A reference to a boolean that can be set to true if you want to cancel the download.</param>
/// <returns>
/// Returns the local file that was downloaded.
/// Use this instead of the localPath parameter because you may have passed no extension asking for us to autodetermine the extension.
/// </returns>
public string DownloadFile(string url, string localPath, Action<int, long, long> progress, ref bool cancel)
{
cancel = false;
var didCancel = false;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.ReadWriteTimeout = 3000;
var buffer = new byte[BufferSize];
var realPath = localPath;
try
{
using (var response = webRequest.GetResponse())
{
// get the total size of this request
var totalSize = 0;
try { totalSize = int.Parse(response.Headers["MediaItemLength"]);
}catch(Exception ex) { throw new NotImplementedException("Get the total size some other way!"); }
// ensure there is a proper extension
if (string.IsNullOrEmpty(Path.GetExtension(localPath)))
{
// the localpath given didn't have an extension.
// we need to try to determine the exention through custom HTTP headers.
string httpHeaderExtension = null;
try
{
httpHeaderExtension = response.Headers["MediaExtension"];
if (string.IsNullOrEmpty(httpHeaderExtension))
throw new Exception("The header was present, but it was empty.");
}
catch (Exception ex)
{
throw new Exception("localPath didn't provide an extension and we couldn't infer would through custom HTTP headers.");
}
// add the correct extension to our local file path
realPath += httpHeaderExtension;
}
if(File.Exists(realPath))
File.Delete(realPath);
using (var responseStream = response.GetResponseStream())
{
using (var dest = new FileStream(realPath, FileMode.CreateNew, FileAccess.Write))
{
long totalBytes = 0;
int currentBlockSize;
while ((currentBlockSize = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
var percentage = (int)(totalBytes * 100.0 / totalSize);
dest.Write(buffer, 0, currentBlockSize);
if (progress != null)
progress(percentage, totalBytes, totalSize);
if (cancel)
{
didCancel = true;
break;
}
}
}
}
}
}catch(Exception ex)
{
// delete the file
if (File.Exists(realPath))
File.Delete(realPath);
throw;
}
// delete the file
if (didCancel && File.Exists(realPath))
File.Delete(realPath);
return realPath;
}
}
代码很简单。我确实包含一些额外/自定义标头以获取总文件大小,以便我可以避免HEAD请求获取值。我需要下载进度的总文件大小。