最近有一个客户需要将文件系统(VM搭建)迁移到Azure存储上,对于Azure存储这里就不多做介绍,但是该客户由于网络原因下载文件的时候经常出现上传中断,所以想在Azure 存储上实现下载的断点续传。下面我就用C#代码实现在Azure存储上下载断点续传,这里只提供一个示例,具体应用需结合业务调整。
由于在前面几篇Blog收到一些批评和建议,这里我们的示例代码也尽量符合实际开发规范。
首先配置Azure存储信息
下载断点续传
//存储连接字符串
static string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];
//存储容器名称
static string containerName = ConfigurationManager.AppSettings["StorageContainer"];
//一次下载数据块大小,这里我设置的是2MB
static int bufferSize = 1024 * 1024 * 2;
static void Main(string[] args)
{
//这里就直接指定一个存储中的Blob文件
string fileName = "aspnet-core.pdf";
DownloadBlockBlobBreakPoint(containerName, fileName);
Console.WriteLine("文件下载成功...");
Console.ReadKey();
} /// <summary>
/// 文件下载(断点续传)
/// </summary>
/// <param name="container"></param>
/// <param name="fileName"></param>
private static void DownloadBlockBlobBreakPoint(string container,string fileName)
{
//这里我没有返回文件流或者byte数组,而是直接在此接口中直接写文件,主要是图方便
//每一个存储中的Blob文件都有一个对应的记录该文件下载到哪一位置的文本文件
string flagFile = Path.GetFileNameWithoutExtension(fileName) + ".txt";
CloudBlockBlob blockBlob = GetBlockBlob(container, fileName);
byte[] buffer = new byte[bufferSize];
blockBlob.FetchAttributes();
long blobSize = blockBlob.Properties.Length;
int blobCount = (int)(blobSize / bufferSize) + 1;
int currentCount = 0;
if (!File.Exists(flagFile))
{
FileStream fs = File.Create(flagFile);
fs.Close();
fs.Dispose();
}else
{
string[] ids = File.ReadAllLines(flagFile);
currentCount = ids.Length;
}
for (int i = currentCount; i < blobCount; i++)
{
int totalNumber = blockBlob.DownloadRangeToByteArray(buffer, 0, currentCount * bufferSize, bufferSize);
Console.WriteLine(i.ToString());
if (totalNumber > 0)
{
using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.Write))
{
fs.Write(buffer, 0, buffer.Length);
}
File.AppendAllLines(flagFile, new List<string>() { Guid.NewGuid().ToString() });
currentCount++;
}
else
{
break;
}
}
} /// <summary>
/// 获取Azure存储中指定的Blob文件
/// </summary>
/// <param name="container"></param>
/// <param name="fileName"></param>
/// <returns></returns>
private static CloudBlockBlob GetBlockBlob(string container, string fileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference(container);
blobContainer.CreateIfNotExists();
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
return blockBlob;
}
虽然客户只提出了下载断点续传,但是要写就索性写完整一点,下面我把上传断点续传也实现了。
/// <summary>
/// 文件上传(断点续传)
/// </summary>
/// <param name="container"></param>
/// <param name="path"></param>
private static void UploadBlockBlobBreakPoint(string container,string path)
{
string flagFile = Path.GetFileNameWithoutExtension(path) + ".txt";
string blobName = Path.GetFileName(path);
CloudBlockBlob blockBlob = GetBlockBlob(container, blobName); byte[] buffer = new byte[bufferSize];
int fileSize = File.ReadAllBytes(path).Length;
int fileCount = fileSize / bufferSize + ;
int currentCount = ;
List<string> blobIdList = new List<string>();
if (!File.Exists(flagFile))
{
FileStream fs = File.Create(flagFile);
fs.Close();
fs.Dispose();
}
else
{
string[] blobIds = File.ReadAllLines(flagFile);
currentCount = blobIds.Length;
blobIdList.AddRange(blobIds);
} for (int i = currentCount ; i < fileCount; i++)
{
using (FileStream fs=new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,bufferSize))
{
fs.Read(buffer, , buffer.Length); } using(MemoryStream ms =new MemoryStream(buffer, , buffer.Length))
{
string blobId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));
blockBlob.PutBlock(blobId, ms, null);
blobIdList.Add(blobId);
File.AppendAllLines(flagFile, new List<string>() { blobId });
}
}
blockBlob.PutBlockList(blobIdList);
}