added SupportsMultiThreading flag for File based Zips

This commit is contained in:
Adam Hathcock
2025-11-27 12:11:10 +00:00
parent 1984da6997
commit af7e270b2d
7 changed files with 41 additions and 28 deletions

View File

@@ -23,5 +23,7 @@ public class ZipArchiveEntry : ZipEntry, IArchiveEntry
public bool IsComplete => true;
public override bool SupportsMultiThreading => Parts.Single().SupportsMultiThreading;
#endregion
}

View File

@@ -87,4 +87,5 @@ public abstract class Entry : IEntry
/// Entry file attribute.
/// </summary>
public virtual int? Attrib => throw new NotImplementedException();
public virtual bool SupportsMultiThreading => false;
}

View File

@@ -14,4 +14,7 @@ public abstract class FilePart
internal abstract Stream? GetCompressedStream();
internal abstract Stream? GetRawStream();
internal bool Skipped { get; set; }
public virtual bool SupportsMultiThreading => false;
}

View File

@@ -21,4 +21,5 @@ public interface IEntry
DateTime? LastModifiedTime { get; }
long Size { get; }
int? Attrib { get; }
public bool SupportsMultiThreading { get; }
}

View File

@@ -1,20 +1,10 @@
using System;
using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
namespace SharpCompress.Common.Zip;
internal class FileInfoZipFilePart : FilePart
{
internal FileInfoZipFilePart(
DirectoryEntryHeader header,
FileInfo file
)
: base(header.ArchiveEncoding)
{
}
}
internal class SeekableZipFilePart : ZipFilePart
{
private bool _isLocalHeaderLoaded;
@@ -42,8 +32,20 @@ internal class SeekableZipFilePart : ZipFilePart
protected override Stream CreateBaseStream()
{
if (BaseStream is SourceStream ss)
{
if (ss.IsFileMode)
{
var fileStream = ss.CurrentFile.OpenRead();
fileStream.Position = Header.DataStartPosition.NotNull();
return fileStream;
}
}
BaseStream.Position = Header.DataStartPosition.NotNull();
return BaseStream;
}
public override bool SupportsMultiThreading => BaseStream is SourceStream ss && ss.IsFileMode;
}

View File

@@ -15,7 +15,7 @@ public class SourceStream : Stream, IStreamStack
#endif
int IStreamStack.DefaultBufferSize { get; set; }
Stream IStreamStack.BaseStream() => _streams[_stream];
Stream IStreamStack.BaseStream() => _streams[_streamIndex];
int IStreamStack.BufferSize
{
@@ -35,7 +35,7 @@ public class SourceStream : Stream, IStreamStack
private readonly List<Stream> _streams;
private readonly Func<int, FileInfo?>? _getFilePart;
private readonly Func<int, Stream?>? _getStreamPart;
private int _stream;
private int _streamIndex;
public SourceStream(FileInfo file, Func<int, FileInfo?> getPart, ReaderOptions options)
: this(null, null, file, getPart, options) { }
@@ -59,7 +59,7 @@ public class SourceStream : Stream, IStreamStack
if (!IsFileMode)
{
_streams.Add(stream!);
_streams.Add(stream.NotNull("stream is null"));
_getStreamPart = getStreamPart;
_getFilePart = _ => null;
if (stream is FileStream fileStream)
@@ -69,12 +69,12 @@ public class SourceStream : Stream, IStreamStack
}
else
{
_files.Add(file!);
_files.Add(file.NotNull("file is null"));
_streams.Add(_files[0].OpenRead());
_getFilePart = getFilePart;
_getStreamPart = _ => null;
}
_stream = 0;
_streamIndex = 0;
_prevSize = 0;
#if DEBUG_STREAMS
@@ -93,10 +93,12 @@ public class SourceStream : Stream, IStreamStack
public ReaderOptions ReaderOptions { get; }
public bool IsFileMode { get; }
public IEnumerable<FileInfo> Files => _files;
public IEnumerable<Stream> Streams => _streams;
public IReadOnlyList<FileInfo> Files => _files;
public IReadOnlyList<Stream> Streams => _streams;
private Stream Current => _streams[_stream];
private Stream Current => _streams[_streamIndex];
public FileInfo CurrentFile => _files[_streamIndex];
public bool LoadStream(int index) //ensure all parts to id are loaded
{
@@ -107,7 +109,7 @@ public class SourceStream : Stream, IStreamStack
var f = _getFilePart.NotNull("GetFilePart is null")(_streams.Count);
if (f == null)
{
_stream = _streams.Count - 1;
_streamIndex = _streams.Count - 1;
return false;
}
//throw new Exception($"File part {idx} not available.");
@@ -119,7 +121,7 @@ public class SourceStream : Stream, IStreamStack
var s = _getStreamPart.NotNull("GetStreamPart is null")(_streams.Count);
if (s == null)
{
_stream = _streams.Count - 1;
_streamIndex = _streams.Count - 1;
return false;
}
//throw new Exception($"Stream part {idx} not available.");
@@ -137,10 +139,10 @@ public class SourceStream : Stream, IStreamStack
{
if (LoadStream(idx))
{
_stream = idx;
_streamIndex = idx;
}
return _stream == idx;
return _streamIndex == idx;
}
public override bool CanRead => true;
@@ -184,7 +186,7 @@ public class SourceStream : Stream, IStreamStack
var length = Current.Length;
// Load next file if present
if (!SetStream(_stream + 1))
if (!SetStream(_streamIndex + 1))
{
break;
}
@@ -223,7 +225,7 @@ public class SourceStream : Stream, IStreamStack
while (_prevSize + Current.Length < pos)
{
_prevSize += Current.Length;
SetStream(_stream + 1);
SetStream(_streamIndex + 1);
}
}
@@ -273,7 +275,7 @@ public class SourceStream : Stream, IStreamStack
var length = Current.Length;
// Load next file if present
if (!SetStream(_stream + 1))
if (!SetStream(_streamIndex + 1))
{
break;
}
@@ -322,7 +324,7 @@ public class SourceStream : Stream, IStreamStack
var length = Current.Length;
// Load next file if present
if (!SetStream(_stream + 1))
if (!SetStream(_streamIndex + 1))
{
break;
}

View File

@@ -134,6 +134,7 @@ public class ArchiveTests : ReaderTests
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Assert.False(entry.SupportsMultiThreading);
entry.WriteToDirectory(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
@@ -277,6 +278,7 @@ public class ArchiveTests : ReaderTests
{
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Assert.True(entry.SupportsMultiThreading);
entry.WriteToDirectory(
SCRATCH_FILES_PATH,
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }