作为我大学即将要做的一个项目,我需要编写一个客户端从服务器下载媒体文件并将其写入本地磁盘。由于这些文件可能非常大,因此我需要实现分段下载和序列化以避免过度使用内存。
我的解决方案是:
我的解决方案是:
namespace PartialDownloadTester
{
using System;
using System.Diagnostics.Contracts;
using System.IO;
using System.Net;
using System.Text;
public class DownloadClient
{
public static void Main(string[] args)
{
var dlc = new DownloadClient(args[0], args[1], args[2]);
dlc.DownloadAndSaveToDisk();
Console.ReadLine();
}
private WebRequest request;
// directory of file
private string dir;
// full file identifier
private string filePath;
public DownloadClient(string uri, string fileName, string fileType)
{
this.request = WebRequest.Create(uri);
this.request.Method = "GET";
var sb = new StringBuilder();
sb.Append("C:\\testdata\\DownloadedData\\");
this.dir = sb.ToString();
sb.Append(fileName + "." + fileType);
this.filePath = sb.ToString();
}
public void DownloadAndSaveToDisk()
{
// make sure directory exists
this.CreateDir();
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine("Content length: " + response.ContentLength);
var rStream = response.GetResponseStream();
int bytesRead = -1;
do
{
var buf = new byte[2048];
bytesRead = rStream.Read(buf, 0, buf.Length);
rStream.Flush();
this.SerializeFileChunk(buf);
}
while (bytesRead != 0);
}
private void CreateDir()
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
}
private void SerializeFileChunk(byte[] bytes)
{
Contract.Requires(!Object.ReferenceEquals(bytes, null));
FileStream fs = File.Open(filePath, FileMode.Append);
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
}
}
为了测试目的,我使用了以下参数:
"http://itu.dk/people/janv/mufc_abc.jpg" "mufc_abc" "jpg"
然而,图片是不完整的(只有前面10%左右是正确的),即使内容长度打印为63780,这是图像的实际大小。
所以我的问题是:
- 这是部分下载和序列化的正确方法,还是有更好/更简单的方法?
- 响应流中的全部内容是否存储在客户端内存中?如果是这种情况,我是否需要使用HttpWebRequest.AddRange从服务器部分下载数据以保留客户端的内存?
- 为什么序列化失败并且我得到了一张损坏的图片?
- 当我使用FileMode.Append时,是否引入了很多开销?(msdn表明此选项“定位到文件的末尾”)
提前感谢。