This repository was archived by the owner on Aug 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 371
/
Copy pathFileReadStream.cs
167 lines (154 loc) · 7.65 KB
/
FileReadStream.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// -----------------------------------------------------------------------------------------
// <copyright file="FileReadStream.cs" company="Microsoft">
// Copyright 2013 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
// -----------------------------------------------------------------------------------------
namespace Microsoft.Azure.Storage.File
{
using Microsoft.Azure.Storage.Core;
using Microsoft.Azure.Storage.Core.Util;
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
#if !NETCORE
using Windows.Storage.Streams;
#endif
/// <summary>
/// Provides an input stream to read a given file resource.
/// </summary>
internal sealed class FileReadStream : FileReadStreamBase
{
/// <summary>
/// Initializes a new instance of the <see cref="FileReadStream"/> class.
/// </summary>
/// <param name="file">File reference to read from.</param>
/// <param name="accessCondition">An object that represents the access conditions for the file. If null, no condition is used.</param>
/// <param name="options">An object that specifies additional options for the request.</param>
/// <param name="operationContext">An <see cref="OperationContext"/> object that represents the context for the current operation.</param>
internal FileReadStream(CloudFile file, AccessCondition accessCondition, FileRequestOptions options, OperationContext operationContext)
: base(file, accessCondition, options, operationContext)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FileReadStream"/> class.
/// </summary>
/// <param name="otherStream">Another FileReadStream instance to clone.</param>
internal FileReadStream(FileReadStream otherStream)
: this(otherStream.file, otherStream.accessCondition, otherStream.options, otherStream.operationContext)
{
}
/// <summary>
/// Gets the format of the data.
/// </summary>
/// <value>The format of the data.</value>
public string ContentType
{
get
{
return this.fileProperties.ContentType;
}
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the
/// position within the stream by the number of bytes read.
/// </summary>
/// <param name="buffer">The buffer to read the data into.</param>
/// <param name="offset">The byte offset in buffer at which to begin writing
/// data read from the stream.</param>
/// <param name="count">The maximum number of bytes to read.</param>
/// <returns>The total number of bytes read into the buffer. This can be
/// less than the number of bytes requested if that many bytes are not
/// currently available, or zero (0) if the end of the stream has been reached.</returns>
public override int Read(byte[] buffer, int offset, int count)
{
return this.ReadAsync(buffer, offset, count, CancellationToken.None).Result;
}
/// <summary>
/// Asynchronously reads a sequence of bytes from the current stream, advances the
/// position within the stream by the number of bytes read, and monitors cancellation requests.
/// </summary>
/// <remarks>In the returned <see cref="Task{TElement}"/> object, the value of the integer
/// parameter contains the total number of bytes read into the buffer. The result value can be
/// less than the number of bytes requested if the number of bytes currently available is less
/// than the requested number, or it can be 0 (zero) if the end of the stream has been reached.</remarks>
/// <param name="buffer">The buffer to read the data into.</param>
/// <param name="offset">The byte offset in buffer at which to begin writing
/// data read from the stream.</param>
/// <param name="count">The maximum number of bytes to read.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task that represents the asynchronous read operation.</returns>
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
CommonUtility.AssertNotNull("buffer", buffer);
CommonUtility.AssertInBounds("offset", offset, 0, buffer.Length);
CommonUtility.AssertInBounds("count", count, 0, buffer.Length - offset);
if (this.lastException != null)
{
throw this.lastException;
}
if ((this.currentOffset == this.Length) || (count == 0))
{
return Task.FromResult(0);
}
int readCount = this.ConsumeBuffer(buffer, offset, count);
if (readCount > 0)
{
return Task.FromResult(readCount);
}
return this.DispatchReadAsync(buffer, offset, count, cancellationToken);
}
/// <summary>
/// Dispatches a sync read operation that either reads from the cache or makes a call to
/// the server.
/// </summary>
/// <param name="buffer">The buffer to read the data into.</param>
/// <param name="offset">The byte offset in buffer at which to begin writing
/// data read from the stream.</param>
/// <param name="count">The maximum number of bytes to read.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>Number of bytes read from the stream.</returns>
private async Task<int> DispatchReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
try
{
this.internalBuffer.SetLength(0);
await this.file.DownloadRangeToStreamAsync(
this.internalBuffer,
this.currentOffset,
this.GetReadSize(),
null /* accessCondition */,
this.options,
this.operationContext,
cancellationToken).ConfigureAwait(false);
if (!this.file.Properties.ETag.Equals(this.accessCondition.IfMatchETag, StringComparison.Ordinal))
{
RequestResult reqResult = new RequestResult();
reqResult.HttpStatusMessage = null;
reqResult.HttpStatusCode = (int)HttpStatusCode.PreconditionFailed;
reqResult.ExtendedErrorInformation = null;
throw new StorageException(reqResult, SR.PreconditionFailed, null /* inner */);
}
this.internalBuffer.Seek(0, SeekOrigin.Begin);
return this.ConsumeBuffer(buffer, offset, count);
}
catch (Exception e)
{
this.lastException = e;
throw;
}
}
}
}