@@ -8,13 +8,12 @@ namespace LuYao.ResourcePacker
88{
99 /// <summary>
1010 /// Provides functionality to read resources from a packaged resource file.
11- /// This class is thread-safe for concurrent read operations.
11+ /// This class is thread-safe for concurrent read operations by creating independent FileStream instances per operation .
1212 /// </summary>
1313 public class ResourcePackageReader : IDisposable
1414 {
15- private readonly FileStream _fileStream ;
15+ private readonly string _filePath ;
1616 private readonly Dictionary < string , ResourceEntry > _resourceIndex ;
17- private readonly object _lock = new object ( ) ;
1817 private bool _disposed ;
1918
2019 /// <summary>
@@ -23,14 +22,15 @@ public class ResourcePackageReader : IDisposable
2322 /// <param name="filePath">The path to the resource package file.</param>
2423 public ResourcePackageReader ( string filePath )
2524 {
26- _fileStream = new FileStream ( filePath , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
25+ _filePath = filePath ?? throw new ArgumentNullException ( nameof ( filePath ) ) ;
2726 _resourceIndex = new Dictionary < string , ResourceEntry > ( ) ;
2827 LoadIndex ( ) ;
2928 }
3029
3130 private void LoadIndex ( )
3231 {
33- using var reader = new BinaryReader ( _fileStream , System . Text . Encoding . UTF8 , leaveOpen : true ) ;
32+ using var fileStream = new FileStream ( _filePath , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
33+ using var reader = new BinaryReader ( fileStream , System . Text . Encoding . UTF8 , leaveOpen : false ) ;
3434
3535 // Read version number
3636 var version = reader . ReadByte ( ) ;
@@ -52,7 +52,7 @@ private void LoadIndex()
5252 }
5353
5454 // Calculate offsets based on the current position
55- long currentOffset = _fileStream . Position ;
55+ long currentOffset = fileStream . Position ;
5656 foreach ( var ( key , length ) in indexEntries )
5757 {
5858 _resourceIndex [ key ] = new ResourceEntry
@@ -94,15 +94,15 @@ public Task<byte[]> ReadResourceAsync(string resourceKey)
9494
9595 var buffer = new byte [ entry . Length ] ;
9696
97- // Lock to ensure thread-safe access to FileStream
98- lock ( _lock )
97+ // Create a new FileStream for this read operation ( thread-safe via FileShare.Read)
98+ using ( var fileStream = new FileStream ( _filePath , FileMode . Open , FileAccess . Read , FileShare . Read ) )
9999 {
100- _fileStream . Seek ( entry . Offset , SeekOrigin . Begin ) ;
100+ fileStream . Seek ( entry . Offset , SeekOrigin . Begin ) ;
101101
102102 int totalRead = 0 ;
103103 while ( totalRead < entry . Length )
104104 {
105- int bytesRead = _fileStream . Read ( buffer , totalRead , entry . Length - totalRead ) ;
105+ int bytesRead = fileStream . Read ( buffer , totalRead , entry . Length - totalRead ) ;
106106 if ( bytesRead == 0 )
107107 throw new EndOfStreamException ( $ "Unexpected end of stream while reading resource '{ resourceKey } '.") ;
108108 totalRead += bytesRead ;
@@ -150,15 +150,15 @@ public byte[] ReadResource(string resourceKey)
150150
151151 var buffer = new byte [ entry . Length ] ;
152152
153- // Lock to ensure thread-safe access to FileStream
154- lock ( _lock )
153+ // Create a new FileStream for this read operation ( thread-safe via FileShare.Read)
154+ using ( var fileStream = new FileStream ( _filePath , FileMode . Open , FileAccess . Read , FileShare . Read ) )
155155 {
156- _fileStream . Seek ( entry . Offset , SeekOrigin . Begin ) ;
156+ fileStream . Seek ( entry . Offset , SeekOrigin . Begin ) ;
157157
158158 int totalRead = 0 ;
159159 while ( totalRead < entry . Length )
160160 {
161- int bytesRead = _fileStream . Read ( buffer , totalRead , entry . Length - totalRead ) ;
161+ int bytesRead = fileStream . Read ( buffer , totalRead , entry . Length - totalRead ) ;
162162 if ( bytesRead == 0 )
163163 throw new EndOfStreamException ( $ "Unexpected end of stream while reading resource '{ resourceKey } '.") ;
164164 totalRead += bytesRead ;
@@ -204,20 +204,17 @@ public Stream GetStream(string resourceKey)
204204 if ( ! _resourceIndex . TryGetValue ( resourceKey , out var entry ) )
205205 throw new KeyNotFoundException ( $ "Resource with key '{ resourceKey } ' not found.") ;
206206
207- // Create a SubStream wrapper that provides a read-only view of a portion of the file
208- return new SubStream ( _fileStream , entry . Offset , entry . Length , _lock ) ;
207+ // Read the resource data into memory and return a MemoryStream
208+ var buffer = ReadResource ( resourceKey ) ;
209+ return new MemoryStream ( buffer , writable : false ) ;
209210 }
210211
211212 /// <summary>
212213 /// Releases the resources used by the <see cref="ResourcePackageReader"/>.
213214 /// </summary>
214215 public void Dispose ( )
215216 {
216- if ( ! _disposed )
217- {
218- _fileStream ? . Dispose ( ) ;
219- _disposed = true ;
220- }
217+ _disposed = true ;
221218 }
222219 }
223220
@@ -226,104 +223,4 @@ internal class ResourceEntry
226223 public long Offset { get ; set ; }
227224 public int Length { get ; set ; }
228225 }
229-
230- /// <summary>
231- /// A stream wrapper that provides a read-only view of a portion of another stream.
232- /// This class is thread-safe when used with a lock object.
233- /// </summary>
234- internal class SubStream : Stream
235- {
236- private readonly Stream _baseStream ;
237- private readonly long _offset ;
238- private readonly long _length ;
239- private readonly object _lock ;
240- private long _position ;
241-
242- public SubStream ( Stream baseStream , long offset , long length , object lockObject )
243- {
244- _baseStream = baseStream ?? throw new ArgumentNullException ( nameof ( baseStream ) ) ;
245- _lock = lockObject ?? throw new ArgumentNullException ( nameof ( lockObject ) ) ;
246- _offset = offset ;
247- _length = length ;
248- _position = 0 ;
249- }
250-
251- public override bool CanRead => true ;
252- public override bool CanSeek => true ;
253- public override bool CanWrite => false ;
254- public override long Length => _length ;
255-
256- public override long Position
257- {
258- get => _position ;
259- set
260- {
261- if ( value < 0 || value > _length )
262- throw new ArgumentOutOfRangeException ( nameof ( value ) ) ;
263- _position = value ;
264- }
265- }
266-
267- public override int Read ( byte [ ] buffer , int offset , int count )
268- {
269- if ( buffer == null )
270- throw new ArgumentNullException ( nameof ( buffer ) ) ;
271- if ( offset < 0 )
272- throw new ArgumentOutOfRangeException ( nameof ( offset ) ) ;
273- if ( count < 0 )
274- throw new ArgumentOutOfRangeException ( nameof ( count ) ) ;
275- if ( buffer . Length - offset < count )
276- throw new ArgumentException ( "Invalid offset/count combination" ) ;
277-
278- long remaining = _length - _position ;
279- if ( remaining <= 0 )
280- return 0 ;
281-
282- int toRead = ( int ) Math . Min ( count , remaining ) ;
283- int bytesRead ;
284-
285- // Lock to ensure thread-safe access to the base stream
286- lock ( _lock )
287- {
288- _baseStream . Seek ( _offset + _position , SeekOrigin . Begin ) ;
289- bytesRead = _baseStream . Read ( buffer , offset , toRead ) ;
290- }
291-
292- _position += bytesRead ;
293-
294- return bytesRead ;
295- }
296-
297- public override long Seek ( long offset , SeekOrigin origin )
298- {
299- long newPosition = origin switch
300- {
301- SeekOrigin . Begin => offset ,
302- SeekOrigin . Current => _position + offset ,
303- SeekOrigin . End => _length + offset ,
304- _ => throw new ArgumentException ( "Invalid seek origin" , nameof ( origin ) )
305- } ;
306-
307- if ( newPosition < 0 || newPosition > _length )
308- throw new ArgumentOutOfRangeException ( nameof ( offset ) ) ;
309-
310- _position = newPosition ;
311- return _position ;
312- }
313-
314- public override void Flush ( )
315- {
316- // Read-only stream, nothing to flush
317- }
318-
319- public override void SetLength ( long value )
320- {
321- throw new NotSupportedException ( "Cannot set length on a read-only stream." ) ;
322- }
323-
324- public override void Write ( byte [ ] buffer , int offset , int count )
325- {
326- throw new NotSupportedException ( "Cannot write to a read-only stream." ) ;
327- }
328- }
329226}
0 commit comments