@@ -131,8 +131,11 @@ public void Close()
131131
132132 public async Task < LocalFile > CopyFromStreamAsync ( Stream stream , CancellationToken cancellationToken = default )
133133 {
134- var fs = FileStream ;
135- await stream . CopyToAsync ( fs , cancellationToken ) ;
134+ await using var fs = FileStream ;
135+ fs . SetLength ( 0 ) ;
136+ fs . Position = 0 ;
137+ await stream . CopyToAsync ( fs , cancellationToken ) . ConfigureAwait ( false ) ;
138+ await fs . FlushAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
136139 return this ;
137140 }
138141
@@ -180,6 +183,11 @@ public static LocalFile FromTempFile()
180183 return new LocalFile ( ) ;
181184 }
182185
186+ public Stream OpenReadStream ( bool disposeOwner = true )
187+ {
188+ return new LocalFileReadStream ( this , disposeOwner ) ;
189+ }
190+
183191 #region Read
184192
185193 public string ReadAllText ( )
@@ -304,4 +312,136 @@ public Task WriteAllBytesAsync(byte[] bytes, CancellationToken cancellationToken
304312 }
305313
306314 #endregion
307- }
315+
316+ private sealed class LocalFileReadStream : Stream
317+ {
318+ private readonly LocalFile _owner ;
319+ private readonly FileStream _stream ;
320+ private readonly bool _disposeOwner ;
321+ private bool _disposed ;
322+
323+ public LocalFileReadStream ( LocalFile owner , bool disposeOwner )
324+ {
325+ _owner = owner ;
326+ _disposeOwner = disposeOwner ;
327+ _stream = new FileStream ( owner . FilePath , new FileStreamOptions
328+ {
329+ Mode = FileMode . Open ,
330+ Access = FileAccess . Read ,
331+ Share = FileShare . Read ,
332+ Options = FileOptions . Asynchronous
333+ } ) ;
334+ }
335+
336+ public override bool CanRead => _stream . CanRead ;
337+
338+ public override bool CanSeek => _stream . CanSeek ;
339+
340+ public override bool CanWrite => _stream . CanWrite ;
341+
342+ public override long Length => _stream . Length ;
343+
344+ public override long Position
345+ {
346+ get => _stream . Position ;
347+ set => _stream . Position = value ;
348+ }
349+
350+ public override void Flush ( ) => _stream . Flush ( ) ;
351+
352+ public override Task FlushAsync ( CancellationToken cancellationToken )
353+ {
354+ return _stream . FlushAsync ( cancellationToken ) ;
355+ }
356+
357+ public override int Read ( byte [ ] buffer , int offset , int count )
358+ {
359+ return _stream . Read ( buffer , offset , count ) ;
360+ }
361+
362+ public override int Read ( Span < byte > buffer )
363+ {
364+ return _stream . Read ( buffer ) ;
365+ }
366+
367+ public override ValueTask < int > ReadAsync ( Memory < byte > buffer , CancellationToken cancellationToken = default )
368+ {
369+ return _stream . ReadAsync ( buffer , cancellationToken ) ;
370+ }
371+
372+ public override Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
373+ {
374+ return _stream . ReadAsync ( buffer , offset , count , cancellationToken ) ;
375+ }
376+
377+ public override long Seek ( long offset , SeekOrigin origin )
378+ {
379+ return _stream . Seek ( offset , origin ) ;
380+ }
381+
382+ public override void SetLength ( long value )
383+ {
384+ _stream . SetLength ( value ) ;
385+ }
386+
387+ public override void Write ( byte [ ] buffer , int offset , int count )
388+ {
389+ _stream . Write ( buffer , offset , count ) ;
390+ }
391+
392+ public override void Write ( ReadOnlySpan < byte > buffer )
393+ {
394+ _stream . Write ( buffer ) ;
395+ }
396+
397+ public override Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
398+ {
399+ return _stream . WriteAsync ( buffer , offset , count , cancellationToken ) ;
400+ }
401+
402+ public override ValueTask WriteAsync ( ReadOnlyMemory < byte > buffer , CancellationToken cancellationToken = default )
403+ {
404+ return _stream . WriteAsync ( buffer , cancellationToken ) ;
405+ }
406+
407+ protected override void Dispose ( bool disposing )
408+ {
409+ if ( _disposed )
410+ {
411+ base . Dispose ( disposing ) ;
412+ return ;
413+ }
414+
415+ if ( disposing )
416+ {
417+ _stream . Dispose ( ) ;
418+
419+ if ( _disposeOwner )
420+ {
421+ _owner . Dispose ( ) ;
422+ }
423+ }
424+
425+ _disposed = true ;
426+ base . Dispose ( disposing ) ;
427+ }
428+
429+ public override async ValueTask DisposeAsync ( )
430+ {
431+ if ( _disposed )
432+ {
433+ await ValueTask . CompletedTask ;
434+ return ;
435+ }
436+
437+ await _stream . DisposeAsync ( ) ;
438+
439+ if ( _disposeOwner )
440+ {
441+ await _owner . DisposeAsync ( ) ;
442+ }
443+
444+ _disposed = true ;
445+ }
446+ }
447+ }
0 commit comments