C# 如何跟踪异步文件上载到azure存储的进度

C# 如何跟踪异步文件上载到azure存储的进度,c#,file-upload,azure,azure-storage,azure-storage-blobs,C#,File Upload,Azure,Azure Storage,Azure Storage Blobs,是否有方法跟踪文件上载到Azure存储容器的进度?我正在尝试制作一个控制台应用程序,用于使用C#将数据上传到Azure 我当前的代码如下所示: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Micro

是否有方法跟踪文件上载到Azure存储容器的进度?我正在尝试制作一个控制台应用程序,用于使用C#将数据上传到Azure

我当前的代码如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using System.Configuration;
using System.IO;
using System.Threading;

namespace AdoAzure
{
    class Program
    {
        static void Main(string[] args)
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
            ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference("adokontajnerneki");
            container.CreateIfNotExists();
            CloudBlobClient myBlobClient = storageAccount.CreateCloudBlobClient();
            CloudBlockBlob myBlob = container.GetBlockBlobReference("racuni.adt");
            CancellationToken ca = new CancellationToken();
            var ado = myBlob.UploadFromFileAsync(@"c:\bo\racuni.adt", FileMode.Open, ca);
            Console.WriteLine(ado.Status); //Does Not Help Much
            ado.ContinueWith(t =>
            {
                Console.WriteLine("It is over"); //this is working OK
            });
            Console.WriteLine(ado.Status); //Does Not Help Much
            Console.WriteLine("theEnd");
            Console.ReadKey();
        }
    }
}

这段代码运行得很好,但我希望有某种进度条,这样用户就可以看到正在运行的任务。WindowsAzure.Storage.Blob名称空间中是否有我可以使用的东西,比如帽子里的兔子?

我认为这是不可能的,因为上传文件是一项单独的任务,即使在内部文件被分成多个块,这些块被上传,代码实际上也会等待整个任务完成

一种可能是手动将文件分割成块,并使用方法异步上传这些块。一旦上传了所有块,就可以调用方法来提交blob。请参阅下面的代码,它实现了以下功能:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials("accountname", "accountkey"), true);
        static void Main(string[] args)
        {
            CloudBlobClient myBlobClient = storageAccount.CreateCloudBlobClient();
            myBlobClient.SingleBlobUploadThresholdInBytes = 1024 * 1024;
            CloudBlobContainer container = myBlobClient.GetContainerReference("adokontajnerneki");
            //container.CreateIfNotExists();
            CloudBlockBlob myBlob = container.GetBlockBlobReference("cfx.zip");
            var blockSize = 256 * 1024;
            myBlob.StreamWriteSizeInBytes = blockSize;
            var fileName = @"D:\cfx.zip";
            long bytesToUpload = (new FileInfo(fileName)).Length;
            long fileSize = bytesToUpload;

            if (bytesToUpload < blockSize)
            {
                CancellationToken ca = new CancellationToken();
                var ado = myBlob.UploadFromFileAsync(fileName, FileMode.Open, ca);
                Console.WriteLine(ado.Status); //Does Not Help Much
                ado.ContinueWith(t =>
                {
                    Console.WriteLine("Status = " + t.Status);
                    Console.WriteLine("It is over"); //this is working OK
                });
            }
            else
            {
                List<string> blockIds = new List<string>();
                int index = 1;
                long startPosition = 0;
                long bytesUploaded = 0;
                do
                {
                    var bytesToRead = Math.Min(blockSize, bytesToUpload);
                    var blobContents = new byte[bytesToRead];
                    using (FileStream fs = new FileStream(fileName, FileMode.Open))
                    {
                        fs.Position = startPosition;
                        fs.Read(blobContents, 0, (int)bytesToRead);
                    }
                    ManualResetEvent mre = new ManualResetEvent(false);
                    var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString("d6")));
                    Console.WriteLine("Now uploading block # " + index.ToString("d6"));
                    blockIds.Add(blockId);
                    var ado = myBlob.PutBlockAsync(blockId, new MemoryStream(blobContents), null);
                    ado.ContinueWith(t =>
                    {
                        bytesUploaded += bytesToRead;
                        bytesToUpload -= bytesToRead;
                        startPosition += bytesToRead;
                        index++;
                        double percentComplete = (double)bytesUploaded / (double)fileSize;
                        Console.WriteLine("Percent complete = " + percentComplete.ToString("P"));
                        mre.Set();
                    });
                    mre.WaitOne();
                }
                while (bytesToUpload > 0);
                Console.WriteLine("Now committing block list");
                var pbl = myBlob.PutBlockListAsync(blockIds);
                pbl.ContinueWith(t =>
                {
                    Console.WriteLine("Blob uploaded completely.");
                });
            }
            Console.ReadKey();
        }
    }
}
使用Microsoft.WindowsAzure.Storage;
使用Microsoft.WindowsAzure.Storage.Auth;
使用Microsoft.WindowsAzure.Storage.Blob;
使用制度;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
班级计划
{
静态CloudStorageAccount storageAccount=新的CloudStorageAccount(新的StorageCredentials(“accountname”、“accountkey”),true);
静态void Main(字符串[]参数)
{
CloudBlobClient myBlobClient=storageAccount.CreateCloudBlobClient();
myBlobClient.SingleBlobUploadThresholdInBytes=1024*1024;
CloudBlobContainer container=myBlobClient.GetContainerReference(“adokontajnerneki”);
//container.CreateIfNotExists();
CloudBlockBlob myBlob=container.GetBlockBlobReference(“cfx.zip”);
var blockSize=256*1024;
myBlob.StreamWriteSizeInBytes=块大小;
var fileName=@“D:\cfx.zip”;
long bytesToUpload=(新文件信息(文件名)).Length;
long fileSize=bytesToUpload;
if(bytesToUpload
{
Console.WriteLine(“Status=“+t.Status”);
Console.WriteLine(“结束”);//这工作正常
});
}
其他的
{
List blockIds=新列表();
int指数=1;
长起始位置=0;
长字节数=0;
做
{
var bytesToRead=Math.Min(块大小,bytesToUpload);
var blobContents=新字节[bytesToRead];
使用(FileStream fs=newfilestream(fileName,FileMode.Open))
{
fs.位置=起始位置;
读取(blobContents,0,(int)bytesToRead);
}
ManualResetEvent mre=新的ManualResetEvent(错误);
var blockId=Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString(“d6”));
Console.WriteLine(“现在正在上传块#”+index.ToString(“d6”);
blockId.Add(blockId);
var ado=myBlob.putblocksync(blockId,新内存流(blobContents),null);
ado.ContinueWith(t=>
{
bytesUpload+=bytesToRead;
bytesToUpload-=bytesToRead;
startPosition+=bytesToRead;
索引++;
完成双百分比=(双)字节上载/(双)文件大小;
Console.WriteLine(“完成百分比=”+完成百分比.ToString(“P”);
mre.Set();
});
韦通先生();
}
while(bytesToUpload>0);
WriteLine(“正在提交阻止列表”);
var pbl=myBlob.PutBlockListAsync(blockIds);
pbl.ContinueWith(t=>
{
Console.WriteLine(“Blob已完全上传”);
});
}
Console.ReadKey();
}
}
}

Gaurav的解决方案运行良好,与之非常相似。这段代码的挑战在于,您只需很少的错误处理就可以完成大量复杂的工作。我并不是说Gaurav的代码有什么问题——它看起来很可靠——但特别是与网络相关的通信代码,有很多变量和问题需要解释

出于这个原因,我修改了我的原始博客,使用存储客户端库中的上载代码(假设来自Azure存储团队的代码比我所能编写的任何代码都更健壮),并使用ProgressStream类跟踪进度。您可以在上看到更新的代码。

这个怎么样

public类observeFileStream:FileStream
{
私人行动;
public observeFileStream(字符串文件名,文件模式,动作回调):base(文件名,模式)
{
_回调=回调;
}
公共重写无效写入(字节[]数组、整数偏移量、整数计数)
{
_回调?.Invoke(长度);
写入(数组、偏移量、计数);
}
公共重写整型读取(字节[]数组、整型偏移量、整型计数)
{
_回调?.Invoke(位置);
返回base.Read(数组、偏移量、计数);
}
}
公共类测试
{
私有异步无效上载(字符串文件路径、CloudBlockBlob blob)
{
可观测流fs=nu
public void UploadBlob(string fileToUploadPath)
{
    var file = new FileInfo(fileToUploadPath);
    uploadFileSize = file.Length; //Get the file size. This is need to calculate the file upload progress

    //Initialize a progress handler. When the file is being uploaded, the current uploaded bytes will be published back to us using this progress handler by the Blob Storage Service
    var progressHandler = new Progress();
    progressHandler.ProgressChanged += UploadProgressChanged;

    var blob = new BlobClient(connectionString, containerName, file.Name); //Initialize the blob client
    blob.Upload(fileToUploadPath, progressHandler: progressHandler); //Make sure to pass the progress handler here

}

private void UploadProgressChanged(object sender, long bytesUploaded)
{
    //Calculate the progress and update the progress bar.
    //Note: the bytes uploaded published back to us is in long. In order to calculate the percentage, the value has to be converted to double. 
    //Auto type casting from long to double happens here as part of function call
    Console.WriteLine(GetProgressPercentage(uploadFileSize, bytesUploaded));
}

private double GetProgressPercentage(double totalSize,double currentSize)
{
    return (currentSize / totalSize) * 100;
}
private const string StorageConnectionString = "<Your storage connection string>";
private const string StorageContainerName = "<Your storage container name>";

[HttpPost]
public async Task<IActionResult> UploadFiles(IList<IFormFile> files)
{
    foreach (var file in files)
    {
        var blockBlobClient = new BlockBlobClient(StorageConnectionString, StorageContainerName, file.FileName); // Add Guid to FileName to ensure uniqueness

        using var output = blockBlobClient.OpenWrite(overwrite: true);
        using var input = file.OpenReadStream();

        var buffer = new byte[64 * 1024];
        var totalReadBytes = 0L;
        var readBytes = 0;

        while ((readBytes = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            await output.WriteAsync(buffer, 0, readBytes);

            totalReadBytes += readBytes;

            //progress = Math.Round((totalReadBytes * 1d / sessionUploadFileInfo.FileLength * 100d), 2, MidpointRounding.AwayFromZero);
            //do what you do with the progress, save it in session or however you display it to the user...
            //With WebAPI, I use a static dictionary and a client Id to store file upload progress
            //A separate REST request with client Id gets the file progress' from the dictionary
        }
    }
    return Content("success");
}