最近有一个客户需要将文件系统(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 + 1; int currentCount = 0; 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, 0, buffer.Length); } using(MemoryStream ms =new MemoryStream(buffer, 0, 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); }