使用块 API 处理大文件
处理大文件夹的方法是将其拆分成多个小块数据,然后再处理小块数据。
拆分成块上载
前面我们了解了在单个请求中上载整个Blob的方法,但对于大型Blob,我们需要拆分成小块后再上载,实际上,对于超出64MB的Blob,我们必须使用块API( Put Block 和 Put Block List )进行上载,通过拆分成一系列小块上载有很多好处。
1、允许我们上载大于64MB的Blob。
2、允许我们并行上载Blob。
3、上载失败后,可以重新上载之前上载失败的块,而不用全部重新上载,与断点续传类似。
使用块API
下面的代码都摘自 http://slupload.cloudapp.net ,首先构造一个我们是否使用块的Web请求(当Blob超出64MB时就使用)。
if (UseBlocks)
{
// encode the block name and add it to the query string
currentBlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
uriBuilder.Query = uriBuilder.Query.TrimStart('?') +
string.Format("&comp=block&blockid={0}", currentBlockId);
}
// with or without using blocks, we'll make a PUT request with the data
HttpWebRequest webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uriBuilder.Uri);
webRequest.Method = "PUT";
webRequest.BeginGetRequestStream(new AsyncCallback(WriteToStreamCallback), webRequest);
{
// encode the block name and add it to the query string
currentBlockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
uriBuilder.Query = uriBuilder.Query.TrimStart('?') +
string.Format("&comp=block&blockid={0}", currentBlockId);
}
// with or without using blocks, we'll make a PUT request with the data
HttpWebRequest webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uriBuilder.Uri);
webRequest.Method = "PUT";
webRequest.BeginGetRequestStream(new AsyncCallback(WriteToStreamCallback), webRequest);
如果我们使用块,当我们上载完所有块后,需要调用 Put Block List 提交块。下面的代码构造Web请求。
HttpWebRequest webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(
new Uri(string.Format("{0}&comp=blocklist", UploadUrl)));
webRequest.Method = "PUT";
webRequest.Headers["x-ms-version"] = "2009-09-19"; // x-ms-version is required for put block list!
webRequest.BeginGetRequestStream(new AsyncCallback(BlockListWriteToStreamCallback), webRequest);
new Uri(string.Format("{0}&comp=blocklist", UploadUrl)));
webRequest.Method = "PUT";
webRequest.Headers["x-ms-version"] = "2009-09-19"; // x-ms-version is required for put block list!
webRequest.BeginGetRequestStream(new AsyncCallback(BlockListWriteToStreamCallback), webRequest);
下面的代码创建一个XML文档列出块(我们用它跟踪我们已上载的块),将其作为 Put Block List 调用的主体发送。
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);
var document = new XDocument(
new XElement("BlockList",
from blockId in blockIds
select new XElement("Uncommitted", blockId)));
var writer = XmlWriter.Create(requestStream, new XmlWriterSettings() { Encoding = Encoding.UTF8 });
document.Save(writer);
writer.Flush();
requestStream.Close();
webRequest.BeginGetResponse(new AsyncCallback(BlockListReadHttpResponseCallback), webRequest);
Stream requestStream = webRequest.EndGetRequestStream(asynchronousResult);
var document = new XDocument(
new XElement("BlockList",
from blockId in blockIds
select new XElement("Uncommitted", blockId)));
var writer = XmlWriter.Create(requestStream, new XmlWriterSettings() { Encoding = Encoding.UTF8 });
document.Save(writer);
writer.Flush();
requestStream.Close();
webRequest.BeginGetResponse(new AsyncCallback(BlockListReadHttpResponseCallback), webRequest);
小结
我们用共享访问签名生成了URL,并实现了跨域访问Blob存储,利用块API实现了大文件的上载,将这些功能糅合到一起,外面加上一层漂亮的UI就完美了,于是我们在 Codeplex 上创建了一个“Silverlight多文件上载项目”,上载页面如下图所示。
图 1 用Silverlight实现的多文件上载页面