"流太长"在Azure Blob Storage上传大文件时

时间:2016-12-19 14:58:50

标签: c# .net azure azure-storage-blobs blobstorage

我尝试将大文件(4Gb)上传到Azure Blob存储,但它失败了。 根据这篇文章(https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-blobs),这是我的代码

CloudBlobContainer blobContainer = blobClient.GetContainerReference("my-container-name");
blobContainer.CreateIfNotExistsAsync().Wait();
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference("blob-name");
await blockBlob.UploadFromFileAsync("C:\test.avi");

但是我收到了此错误

  

消息:流太长了   来源:System.Private.CoreLib
  StackTrace:在System.IO.MemoryStream.Write(Byte []缓冲区,Int32   offset,Int32 count)at   Microsoft.WindowsAzure.Storage.Blob.BlobWriteStream.d__5.MoveNext()   在C:\ Program Files中   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \斑点\ BlobWriteStream.cs:线   144   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.Core.Util.StreamExtensions.d__1`1.MoveNext()   在C:\ Program Files中   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \普通\核心\的Util \ StreamExtensions.cs:线   308   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob<> c__DisplayClass20_0< b__0> d.MoveNext()   在C:\ Program Files中   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \斑点\ CloudBlockBlob.cs:线   301   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob<> c__DisplayClass23_0< b__0> d.MoveNext()   在C:\ Program Files中   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \斑点\ CloudBlockBlob.cs:线   397   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)在System.Runtime.CompilerServices.TaskAwaiter.GetResult()
  在   MyCompany.AzureServices.Blob.BlobService.d__7.MoveNext()   在C:\ MyProjectSource \ MyCompany.AzureServices \ Blob \ BlobService.cs:line   79   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)在System.Runtime.CompilerServices.TaskAwaiter.GetResult()
  在   MyCompany.AzureServices.Blob.MyProject.RecordBlobService<> c__DisplayClass1_0< b__0> d.MoveNext()   在   C:\ MyProjectSource \ MyCompany.AzureServices \斑点\ MyProject的\ RecordBlobService.cs:行   25

根据这篇文章(https://www.simple-talk.com/cloud/platform-as-a-service/azure-blob-storage-part-4-uploading-large-blobs/),我尝试为大文件添加更多选项。 这是我的新代码

TimeSpan backOffPeriod = TimeSpan.FromSeconds(2);
int retryCount = 1;
BlobRequestOptions bro = new BlobRequestOptions()
{
    //If the file to upload is more than 67Mo, we send it in multiple parts
    SingleBlobUploadThresholdInBytes = 67108864, //67Mo (maximum)
    //Number of threads used to send data
    ParallelOperationThreadCount = 1,
    //If the block fail, we retry once (retryCount) after 2 seconds (backOffPeriod)
    RetryPolicy = new ExponentialRetry(backOffPeriod, retryCount),
};
blobClient.DefaultRequestOptions = bro;
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference("blob-name");
//If the file is sended in multiple parts, theses parts size are 4Mo
blockBlob.StreamWriteSizeInBytes = 4194304; //4Mo (maximum)
await blockBlob.UploadFromFileAsync("C:\test.avi");

但我又遇到了同样的错误(Stream太长了)。

我在Microsoft.WindowsAzure.Storage库中找到了该函数" UploadFromFileAsync"使用" UploadFromStreamAsync"它使用MemoryStream。我认为我的错误来自于MemoryStream,但它在blob存储文章中写道,blob的最大大小为195Gb。那我怎么想用呢?

我使用的是Microsoft.WindowsAzure.Storage版本7.2.1

谢谢!

更新1:感谢Tom Sun和Zhaoxing Lu,我尝试使用Microsoft.Azure.Storage.DataMovement。
可悲的是,我在" TransferManager.UploadAsync"上收到错误。功能。我试着谷歌但没什么......
有任何想法吗 ?

这是我的代码:

 string storageConnectionString = "myStorageConnectionString";
   string filePath = @"C:\LargeFile.avi";
   string blobName = "large_file.avi";

    CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
    CloudBlobClient blobClient = account.CreateCloudBlobClient();
    CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
    blobContainer.CreateIfNotExists();

   CloudBlockBlob destBlob = blobContainer.GetBlockBlobReference(blobName);
    // Setup the number of the concurrent operations
    TransferManager.Configurations.ParallelOperations = 64;

    // Setup the transfer context and track the upload progress
    var context = new SingleTransferContext();
    UploadOptions uploadOptions = new UploadOptions
    {
        DestinationAccessCondition = AccessCondition.GenerateIfExistsCondition()
    };
    context.ProgressHandler = new Progress<TransferStatus>(progress =>
    {
        Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
    });

    // Upload a local blob
    TransferManager.UploadAsync(filePath, destBlob, uploadOptions, context, CancellationToken.None).Wait();

这是错误:
消息:发生一个或多个错误。 (传输失败:值的格式&#39; *&#39;无效..)
来源:System.Private.CoreLib
StackTrace:

  

at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean   includeTaskCanceledExceptions)at   System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout,   取消语音取消语言)   System.Threading.Tasks.Task.Wait()at   MyCompany.AzureServices.Blob.BlobService.d__7.MoveNext()   在C:\ MyProjectSource \ MyCompany.AzureServices \ Blob \ BlobService.cs:line   96   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)在System.Runtime.CompilerServices.TaskAwaiter.GetResult()
  在   MyCompany.AzureServices.Blob.MyProject.RecordBlobService&LT;&GT; c__DisplayClass1_0&LT; b__0&GT; d.MoveNext()   在   C:\ MyProjectSource \ MyCompany.AzureServices \斑点\ MyProject的\ RecordBlobService.cs:行   25

内部例外:
消息:传输失败:值的格式&#39; *&#39;无效..
资料来源:Microsoft.WindowsAzure.Storage.DataMovement
StackTrace:

  

在   Microsoft.WindowsAzure.Storage.DataMovement.TransferScheduler.d__22.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferScheduler.cs:行   214   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.SingleObjectTransfer.d__7.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferJobs \ SingleObjectTransfer.cs:行   226   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.TransferManager.d__72.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferManager.cs:行   1263

下一个内部异常:
消息:值的格式&#39; *&#39;无效。
资料来源:Microsoft.WindowsAzure.Storage.DataMovement
StackTrace:

  

在   Microsoft.WindowsAzure.Storage.DataMovement.TransferControllers.BlockBlobWriter.HandleFetchAttributesResult(例外   e)in   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferControllers \ TransferWriters \ BlockBlobWriter.cs:行   196点   Microsoft.WindowsAzure.Storage.DataMovement.TransferControllers.BlockBlobWriter.d__18.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferControllers \ TransferWriters \ BlockBlobWriter.cs:行   157   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.TransferControllers.BlockBlobWriter.d__16.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferControllers \ TransferWriters \ BlockBlobWriter.cs:行   83   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.TransferControllers.SyncTransferController.d__13.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferControllers \ SyncTransferController.cs:行   81   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.TransferControllers.TransferControllerBase.d__33.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferControllers \ TransferControllerBase.cs:行   178   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)   Microsoft.WindowsAzure.Storage.DataMovement.TransferScheduler.d__22.MoveNext()   在   C:\本地\詹金斯\工作\ DM_Hotfix \工作区\ LIB \ TransferScheduler.cs:行   208

最后一个内部异常:
消息:值的格式&#39; *&#39;无效。
资料来源:System.Net.Http
StackTrace:

  

at System.Net.Http.Headers.HttpHeaderParser.ParseValue(String value,   对象storeValue,Int32&amp;指数)   System.Net.Http.Headers.EntityTagHeaderValue.Parse(String input)at at   Microsoft.WindowsAzure.Storage.Shared.Protocol.RequestMessageExtensions.ApplyAccessCondition(StorageRequestMessage   C:\ Program Files中的request,AccessCondition accessCondition)   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \共享\协议\ RequestMessageExtensions.cs:线   125点   Microsoft.WindowsAzure.Storage.Blob.CloudBlob&LT;&GT; c__DisplayClass116_0.b__0(RESTCommand 1 cmd, Uri uri, UriQueryBuilder builder, HttpContent cnt, Nullable 1   C:\ Program Files中的serverTimeout,OperationContext ctx)   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \斑点\ CloudBlob.cs:线   1206在   Microsoft.WindowsAzure.Storage.Core.Executor.Executor.d__4`1.MoveNext()   在C:\ Program Files中   (86)\詹金斯\工作空间\ release_dotnet_master \ LIB \ WindowsRuntime \核心\执行人\ Executor.cs:线   91

最后是我的project.json:

  {
  "version": "1.0.0-*",

  "dependencies": {
    "Microsoft.Azure.DocumentDB.Core": "0.1.0-preview",
    "Microsoft.Azure.Storage.DataMovement": "0.4.1",
    "Microsoft.IdentityModel.Protocols": "2.0.0",
    "NETStandard.Library": "1.6.1",
    "MyProject.Data.Entities": "1.0.0-*",
    "MyProject.Settings": "1.0.0-*",
    "WindowsAzure.Storage": "7.2.1"
  },

  "frameworks": {   
    "netcoreapp1.0": {
      "imports": [
        "dnxcore50",
        "portable-net451+win8"
      ],
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0-*"
        }
      }
    }
  }
}

感谢您的帮助!

更新2(工作)

感谢Tom Sun,这是工作代码

string storageConnectionString = "myStorageConnectionString";
     CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
      CloudBlobClient blobClient = account.CreateCloudBlobClient();
      CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
      blobContainer.CreateIfNotExistsAsync().Wait();
      string sourcePath = @"C:\Tom\TestLargeFile.zip";
      CloudBlockBlob destBlob = blobContainer.GetBlockBlobReference("LargeFile.zip");
      // Setup the number of the concurrent operations
      TransferManager.Configurations.ParallelOperations = 64;
      // Setup the transfer context and track the upoload progress
      var context = new SingleTransferContext
      {
          ProgressHandler =
          new Progress<TransferStatus>(
               progress => { Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred); })
       };
      // Upload a local blob
      TransferManager.UploadAsync(sourcePath, destBlob, null, context, CancellationToken.None).Wait();
      Console.WriteLine("Upload finished !");
      Console.ReadKey();

我也添加了

ShouldOverwriteCallback = (source, destination) =>
               {
                   return true;
               },

SingleTransferContext中覆盖blob(如果已存在)。

3 个答案:

答案 0 :(得分:2)

我们可以使用Azure Storage Data Movement Library easily将大型文件上传到Azure blob存储。它适用于我,请尝试使用以下代码。有关Azure存储数据移动库的更多信息,请参阅document

    string storageConnectionString = "storage connection string";
    CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
    CloudBlobClient blobClient = account.CreateCloudBlobClient();
    CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
    blobContainer.CreateIfNotExists();
    string sourcePath = @"C:\Tom\TestLargeFile.zip";
    CloudBlockBlob destBlob = blobContainer.GetBlockBlobReference("LargeFile.zip");
    // Setup the number of the concurrent operations
    TransferManager.Configurations.ParallelOperations = 64;
    // Setup the transfer context and track the upoload progress

    var context = new SingleTransferContext();

    UploadOptions uploadOptions = new UploadOptions
    {
        DestinationAccessCondition = AccessCondition.GenerateIfExistsCondition()
    };
    context.ProgressHandler = new Progress<TransferStatus>(progress =>
    {
        Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
    });
    // Upload a local blob
    TransferManager.UploadAsync(sourcePath, destBlob, uploadOptions,context, CancellationToken.None).Wait();

SDK信息请参阅package.config文件

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net452" />
  <package id="Microsoft.Azure.Storage.DataMovement" version="0.4.1" targetFramework="net452" />
  <package id="Microsoft.Data.Edm" version="5.6.4" targetFramework="net452" />
  <package id="Microsoft.Data.OData" version="5.6.4" targetFramework="net452" />
  <package id="Microsoft.Data.Services.Client" version="5.6.4" targetFramework="net452" />
  <package id="Microsoft.WindowsAzure.ConfigurationManager" version="1.8.0.0" targetFramework="net452" />
  <package id="Newtonsoft.Json" version="6.0.8" targetFramework="net452" />
  <package id="System.Spatial" version="5.6.4" targetFramework="net452" />
  <package id="WindowsAzure.Storage" version="7.2.1" targetFramework="net452" />
</packages>

从azure portal

检查上传的文件

enter image description here

<强>更新

对于.net核心项目代码:

     string storageConnectionString = "myStorageConnectionString";
     CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
      CloudBlobClient blobClient = account.CreateCloudBlobClient();
      CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");
      blobContainer.CreateIfNotExistsAsync().Wait();
      string sourcePath = @"C:\Tom\TestLargeFile.zip";
      CloudBlockBlob destBlob = blobContainer.GetBlockBlobReference("LargeFile.zip");
      // Setup the number of the concurrent operations
      TransferManager.Configurations.ParallelOperations = 64;
      // Setup the transfer context and track the upoload progress
      var context = new SingleTransferContext
      {
          ProgressHandler =
          new Progress<TransferStatus>(
               progress => { Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred); })
       };
      // Upload a local blob
      TransferManager.UploadAsync(sourcePath, destBlob, null, context, CancellationToken.None).Wait();
      Console.WriteLine("Upload finished !");
      Console.ReadKey();

enter image description here

答案 1 :(得分:1)

我们正在积极研究Azure存储客户端库中的问题。

请注意,由于UploadFromFileAsync()对于大量blob来说不是一个可靠而有效的操作,我建议您考虑以下备选方案:

如果您可以接受命令行工具,则可以尝试AzCopy,它能够以高性能传输Azure存储数据,并且可以暂停传输和传输。恢复。

如果您想以编程方式控制转移作业,请使用Azure Storage Data Movement Library,这是AzCopy的核心。

答案 2 :(得分:0)

原始问题已在WindowsAzure.Storage版本8.0中修复。