AZ-204 Blob存储教程代码报错:Stream does not support reading
Azure Blob存储上传报错:Stream does not support reading 修复方案
问题情况
学习微软AZ-204认证的《使用Blob存储开发解决方案》教程时,完全复制教程代码运行,容器可在Azure门户正常创建,但执行文件上传至Blob步骤时抛出以下异常:
Unhandled exception. System.NotSupportedException: Stream does not support reading. at System.IO.Strategies.BufferedFileStreamStrategy.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at System.IO.FileStream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at Azure.Storage.NonDisposingStream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at Azure.Core.RequestContent.StreamContent.WriteToAsync(Stream stream, CancellationToken cancellation) at Azure.Core.Pipeline.HttpClientTransport.PipelineRequest.PipelineContentAdapter.SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask) at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(HttpMessage message, Boolean async) at Azure.Core.Pipeline.HttpPipelineTransportPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline) at Azure.Core.Pipeline.ResponseBodyPolicy.ProcessAsync(HttpMessage message, ReadOnlyMemory`1 pipeline, Boolean async) at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.<ProcessAsync>g__ProcessAsyncInner|4_0(HttpMessage message, ReadOnlyMemory`1 pipeline) onary`2 metadata, IDictionary`2 tags, BlobRequestConditions conditions, Nullable`1 accessTier, BlobImmutabilityPolicy immutabilityPolicy, Nullable`1 legalHold, IProgress`1 progressHandler, UploadTransferValidationOptions transferValidationOverride, String operationName, Boolean async, CancellationToken cancellationToken) at Azure.Storage.Blobs.Specialized.BlockBlobClient.<>c__DisplayClass64_0.<<GetPartitionedUploaderBehaviors>b__0>d.MoveNext() --- End of stack trace from previous location --- at Azure.Storage.PartitionedUploader`2.UploadInternal(Stream content, Nullable`1 expectedContentLength, TServiceSpecificData args, IProgress`1 progressHandler, Boolean async, CancellationToken cancellationToken) at Azure.Storage.Blobs.BlobClient.StagedUploadInternal(Stream content, BlobUploadOptions options, Boolean async, CancellationToken cancellationToken) at Azure.Storage.Blobs.BlobClient.UploadAsync(Stream content) at Program.<<Main>$>g__ProcessAsync|0_0() in C:\Users\[redacted]\Documents\devops\working with blob storage module\az204-blob\Program.cs:line 51 at Program.<Main>$(String[] args) in C:\Users\[redacted]\Documents\devops\working with blob storage module\az204-blob\Program.cs:line 7
执行的完整代码如下:
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; Console.WriteLine("Azure Blob Storage exercise\n"); // Run the examples asynchronously, wait for the results before proceeding ProcessAsync().GetAwaiter().GetResult(); Console.WriteLine("Press enter to exit the sample application."); Console.ReadLine(); static async Task ProcessAsync() { // Copy the connection string from the portal in the variable below. string storageConnectionString = "[redacted]"; // Create a client that can authenticate with a connection string BlobServiceClient blobServiceClient = new BlobServiceClient(storageConnectionString); // COPY EXAMPLE CODE BELOW HERE // CREATE A CONTAINER //Create a unique name for the container string containerName = "wtblob" + Guid.NewGuid().ToString(); // Create the container and return a container client object BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName); Console.WriteLine("A container named '" + containerName + "' has been created. " + "\nTake a minute and verify in the portal." + "\nNext a file will be created and uploaded to the container."); Console.WriteLine("Press 'Enter' to continue."); Console.ReadLine(); // UPLOAD BLOBS TO A CONTAINER // Create a local file in the ./data/ directory for uploading and downloading string localPath = "./data/"; string fileName = "wtfile" + Guid.NewGuid().ToString() + ".txt"; string localFilePath = Path.Combine(localPath, fileName); // Write text to the file await File.WriteAllTextAsync(localFilePath, "Hello, World!"); // Get a reference to the blob BlobClient blobClient = containerClient.GetBlobClient(fileName); Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri); // Open the file and upload its data using (FileStream uploadFileStream = File.OpenWrite(localFilePath)) { await blobClient.UploadAsync(uploadFileStream); uploadFileStream.Close(); } Console.WriteLine("\nThe file was uploaded. We'll verify by listing" + " the blobs next."); Console.WriteLine("Press 'Enter' to continue."); Console.ReadLine(); // LIST THE BLOBS IN A CONTAINER // List blobs in the container Console.WriteLine("Listing blobs..."); await foreach (BlobItem blobItem in containerClient.GetBlobsAsync()) { Console.WriteLine("\t" + blobItem.Name); } Console.WriteLine("\nYou can also verify by looking inside the " + "container in the portal." + "\nNext the blob will be downloaded with an altered file name."); Console.WriteLine("Press 'Enter' to continue."); Console.ReadLine(); // DOWNLOAD BLOBS // Download the blob to a local file // Append the string "DOWNLOADED" before the .txt extension string downloadFilePath = localFilePath.Replace(".txt", "DOWNLOADED.txt"); Console.WriteLine("\nDownloading blob to\n\t{0}\n", downloadFilePath); // Download the blob's contents and save it to a file BlobDownloadInfo download = await blobClient.DownloadAsync(); using (FileStream downloadFileStream = File.OpenWrite(downloadFilePath)) { await download.Content.CopyToAsync(downloadFileStream); } Console.WriteLine("\nLocate the local file in the data directory created earlier to verify it was downloaded."); Console.WriteLine("The next step is to delete the container and local files."); Console.WriteLine("Press 'Enter' to continue."); Console.ReadLine(); // DELETE A CONTAINER // Delete the container and clean up local files created Console.WriteLine("\n\nDeleting blob container..."); await containerClient.DeleteAsync(); Console.WriteLine("Deleting the local source and downloaded files..."); File.Delete(localFilePath); File.Delete(downloadFilePath); Console.WriteLine("Finished cleaning up."); }
修复方案
核心原因
代码中使用File.OpenWrite(localFilePath)打开文件流,该方法返回的是只写模式的流,不支持读取操作;而Azure Blob的UploadAsync()方法需要从流中读取数据完成上传,因此抛出Stream does not support reading异常。
具体修复
将文件打开方式从File.OpenWrite()改为File.OpenRead(),获取可读的文件流:
// 修正后的上传代码块 using (FileStream uploadFileStream = File.OpenRead(localFilePath)) { await blobClient.UploadAsync(uploadFileStream); }
注意:
using语句会自动释放流资源,无需手动调用Close()方法。
额外说明
如果坚持使用File.OpenWrite(),需要在写完文件后将流的位置重置到起始位置,但这种方式没必要(因为已经通过WriteAllTextAsync完成了文件写入),直接使用File.OpenRead()是更简洁正确的方案。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

