mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-24 16:05:27 +00:00
fixed up async writer
This commit is contained in:
@@ -182,7 +182,7 @@ public class GZipFactory
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenAsync(
|
||||
public IAsyncWriter OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -193,7 +193,7 @@ public class GZipFactory
|
||||
{
|
||||
throw new InvalidFormatException("GZip archives only support GZip compression type.");
|
||||
}
|
||||
return Open(stream, writerOptions);
|
||||
return (IAsyncWriter)Open(stream, writerOptions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -294,14 +294,14 @@ public class TarFactory
|
||||
new TarWriter(stream, new TarWriterOptions(writerOptions));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenAsync(
|
||||
public IAsyncWriter OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Open(stream, writerOptions);
|
||||
return (IAsyncWriter)Open(stream, writerOptions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -218,14 +218,14 @@ public class ZipFactory
|
||||
new ZipWriter(stream, new ZipWriterOptions(writerOptions));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWriter OpenAsync(
|
||||
public IAsyncWriter OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Open(stream, writerOptions);
|
||||
return (IAsyncWriter)Open(stream, writerOptions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -8,7 +8,7 @@ using SharpCompress.IO;
|
||||
namespace SharpCompress.Writers;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
public abstract class AbstractWriter(ArchiveType type, WriterOptions writerOptions) : IWriter
|
||||
public abstract class AbstractWriter(ArchiveType type, WriterOptions writerOptions) : IWriter, IAsyncWriter
|
||||
{
|
||||
private bool _isDisposed;
|
||||
|
||||
|
||||
@@ -10,13 +10,18 @@ public interface IWriter : IDisposable
|
||||
{
|
||||
ArchiveType WriterType { get; }
|
||||
void Write(string filename, Stream source, DateTime? modificationTime);
|
||||
void WriteDirectory(string directoryName, DateTime? modificationTime);
|
||||
}
|
||||
|
||||
public interface IAsyncWriter : IDisposable
|
||||
{
|
||||
ArchiveType WriterType { get; }
|
||||
ValueTask WriteAsync(
|
||||
string filename,
|
||||
Stream source,
|
||||
DateTime? modificationTime,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
void WriteDirectory(string directoryName, DateTime? modificationTime);
|
||||
ValueTask WriteDirectoryAsync(
|
||||
string directoryName,
|
||||
DateTime? modificationTime,
|
||||
|
||||
@@ -8,126 +8,118 @@ namespace SharpCompress.Writers;
|
||||
|
||||
public static class IWriterExtensions
|
||||
{
|
||||
public static void Write(this IWriter writer, string entryPath, Stream source) =>
|
||||
writer.Write(entryPath, source, null);
|
||||
|
||||
public static void Write(this IWriter writer, string entryPath, FileInfo source)
|
||||
extension(IWriter writer)
|
||||
{
|
||||
if (!source.Exists)
|
||||
public void Write(string entryPath, Stream source) =>
|
||||
writer.Write(entryPath, source, null);
|
||||
|
||||
public void Write(string entryPath, FileInfo source)
|
||||
{
|
||||
throw new ArgumentException("Source does not exist: " + source.FullName);
|
||||
}
|
||||
using var stream = source.OpenRead();
|
||||
writer.Write(entryPath, stream, source.LastWriteTime);
|
||||
}
|
||||
if (!source.Exists)
|
||||
{
|
||||
throw new ArgumentException("Source does not exist: " + source.FullName);
|
||||
}
|
||||
|
||||
public static void Write(this IWriter writer, string entryPath, string source) =>
|
||||
writer.Write(entryPath, new FileInfo(source));
|
||||
|
||||
public static void WriteAll(
|
||||
this IWriter writer,
|
||||
string directory,
|
||||
string searchPattern = "*",
|
||||
SearchOption option = SearchOption.TopDirectoryOnly
|
||||
) => writer.WriteAll(directory, searchPattern, null, option);
|
||||
|
||||
public static void WriteAll(
|
||||
this IWriter writer,
|
||||
string directory,
|
||||
string searchPattern = "*",
|
||||
Func<string, bool>? fileSearchFunc = null,
|
||||
SearchOption option = SearchOption.TopDirectoryOnly
|
||||
)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
throw new ArgumentException("Directory does not exist: " + directory);
|
||||
using var stream = source.OpenRead();
|
||||
writer.Write(entryPath, stream, source.LastWriteTime);
|
||||
}
|
||||
|
||||
fileSearchFunc ??= n => true;
|
||||
foreach (
|
||||
var file in Directory
|
||||
.EnumerateFiles(directory, searchPattern, option)
|
||||
.Where(fileSearchFunc)
|
||||
public void Write(string entryPath, string source) =>
|
||||
writer.Write(entryPath, new FileInfo(source));
|
||||
|
||||
public void WriteAll(string directory,
|
||||
string searchPattern = "*",
|
||||
SearchOption option = SearchOption.TopDirectoryOnly
|
||||
) => writer.WriteAll(directory, searchPattern, null, option);
|
||||
|
||||
public void WriteAll(string directory,
|
||||
string searchPattern = "*",
|
||||
Func<string, bool>? fileSearchFunc = null,
|
||||
SearchOption option = SearchOption.TopDirectoryOnly
|
||||
)
|
||||
{
|
||||
writer.Write(file.Substring(directory.Length), file);
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
throw new ArgumentException("Directory does not exist: " + directory);
|
||||
}
|
||||
|
||||
fileSearchFunc ??= n => true;
|
||||
foreach (
|
||||
var file in Directory
|
||||
.EnumerateFiles(directory, searchPattern, option)
|
||||
.Where(fileSearchFunc)
|
||||
)
|
||||
{
|
||||
writer.Write(file.Substring(directory.Length), file);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteDirectory(string directoryName) =>
|
||||
writer.WriteDirectory(directoryName, null);
|
||||
}
|
||||
|
||||
public static void WriteDirectory(this IWriter writer, string directoryName) =>
|
||||
writer.WriteDirectory(directoryName, null);
|
||||
extension(IAsyncWriter writer)
|
||||
{
|
||||
public ValueTask WriteAsync(string entryPath,
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAsync(entryPath, source, null, cancellationToken);
|
||||
|
||||
public async ValueTask WriteAsync(string entryPath,
|
||||
FileInfo source,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!source.Exists)
|
||||
{
|
||||
throw new ArgumentException("Source does not exist: " + source.FullName);
|
||||
}
|
||||
using var stream = source.OpenRead();
|
||||
await writer
|
||||
.WriteAsync(entryPath, stream, source.LastWriteTime, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public ValueTask WriteAsync(string entryPath,
|
||||
string source,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAsync(entryPath, new FileInfo(source), cancellationToken);
|
||||
|
||||
public ValueTask WriteAllAsync(string directory,
|
||||
string searchPattern = "*",
|
||||
SearchOption option = SearchOption.TopDirectoryOnly,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAllAsync(directory, searchPattern, null, option, cancellationToken);
|
||||
|
||||
public async ValueTask WriteAllAsync(string directory,
|
||||
string searchPattern = "*",
|
||||
Func<string, bool>? fileSearchFunc = null,
|
||||
SearchOption option = SearchOption.TopDirectoryOnly,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
throw new ArgumentException("Directory does not exist: " + directory);
|
||||
}
|
||||
|
||||
fileSearchFunc ??= n => true;
|
||||
foreach (
|
||||
var file in Directory
|
||||
.EnumerateFiles(directory, searchPattern, option)
|
||||
.Where(fileSearchFunc)
|
||||
)
|
||||
{
|
||||
await writer
|
||||
.WriteAsync(file.Substring(directory.Length), file, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask WriteDirectoryAsync(string directoryName,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteDirectoryAsync(directoryName, null, cancellationToken);
|
||||
}
|
||||
|
||||
// Async extensions
|
||||
public static ValueTask WriteAsync(
|
||||
this IWriter writer,
|
||||
string entryPath,
|
||||
Stream source,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAsync(entryPath, source, null, cancellationToken);
|
||||
|
||||
public static async ValueTask WriteAsync(
|
||||
this IWriter writer,
|
||||
string entryPath,
|
||||
FileInfo source,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!source.Exists)
|
||||
{
|
||||
throw new ArgumentException("Source does not exist: " + source.FullName);
|
||||
}
|
||||
using var stream = source.OpenRead();
|
||||
await writer
|
||||
.WriteAsync(entryPath, stream, source.LastWriteTime, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static ValueTask WriteAsync(
|
||||
this IWriter writer,
|
||||
string entryPath,
|
||||
string source,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAsync(entryPath, new FileInfo(source), cancellationToken);
|
||||
|
||||
public static ValueTask WriteAllAsync(
|
||||
this IWriter writer,
|
||||
string directory,
|
||||
string searchPattern = "*",
|
||||
SearchOption option = SearchOption.TopDirectoryOnly,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteAllAsync(directory, searchPattern, null, option, cancellationToken);
|
||||
|
||||
public static async ValueTask WriteAllAsync(
|
||||
this IWriter writer,
|
||||
string directory,
|
||||
string searchPattern = "*",
|
||||
Func<string, bool>? fileSearchFunc = null,
|
||||
SearchOption option = SearchOption.TopDirectoryOnly,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
throw new ArgumentException("Directory does not exist: " + directory);
|
||||
}
|
||||
|
||||
fileSearchFunc ??= n => true;
|
||||
foreach (
|
||||
var file in Directory
|
||||
.EnumerateFiles(directory, searchPattern, option)
|
||||
.Where(fileSearchFunc)
|
||||
)
|
||||
{
|
||||
await writer
|
||||
.WriteAsync(file.Substring(directory.Length), file, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static ValueTask WriteDirectoryAsync(
|
||||
this IWriter writer,
|
||||
string directoryName,
|
||||
CancellationToken cancellationToken = default
|
||||
) => writer.WriteDirectoryAsync(directoryName, null, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public interface IWriterFactory : IFactory
|
||||
{
|
||||
IWriter Open(Stream stream, WriterOptions writerOptions);
|
||||
|
||||
IWriter OpenAsync(
|
||||
IAsyncWriter OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -31,7 +31,7 @@ public static class WriterFactory
|
||||
/// <param name="writerOptions">Writer options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that returns an IWriter.</returns>
|
||||
public static IWriter OpenAsync(
|
||||
public static IAsyncWriter OpenAsync(
|
||||
Stream stream,
|
||||
ArchiveType archiveType,
|
||||
WriterOptions writerOptions,
|
||||
|
||||
@@ -380,6 +380,20 @@ public class ArchiveTests : ReaderTests
|
||||
return WriterFactory.Open(stream, ArchiveType.Zip, writerOptions);
|
||||
}
|
||||
|
||||
protected static IAsyncWriter CreateWriterWithLevelAsync(
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
int? compressionLevel = null
|
||||
)
|
||||
{
|
||||
var writerOptions = new ZipWriterOptions(compressionType);
|
||||
if (compressionLevel.HasValue)
|
||||
{
|
||||
writerOptions.CompressionLevel = compressionLevel.Value;
|
||||
}
|
||||
return WriterFactory.OpenAsync(stream, ArchiveType.Zip, writerOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies archive content against expected files with CRC32 validation
|
||||
/// </summary>
|
||||
|
||||
@@ -22,7 +22,7 @@ public class GZipWriterAsyncTests : WriterTests
|
||||
FileAccess.Write
|
||||
)
|
||||
)
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.GZip))
|
||||
using (var writer = WriterFactory.OpenAsync(stream, ArchiveType.GZip, CompressionType.GZip))
|
||||
{
|
||||
await writer.WriteAsync("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
|
||||
// Step 1: create a tar file containing a file with the test name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (var writer = WriterFactory.OpenAsync(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
@@ -76,7 +76,7 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
|
||||
// Step 1: create a tar file containing a file with a long name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (var writer = WriterFactory.OpenAsync(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
|
||||
@@ -73,7 +73,7 @@ public class WriterTests : TestBase
|
||||
|
||||
writerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default;
|
||||
|
||||
using var writer = WriterFactory.Open(stream, _type, writerOptions);
|
||||
using var writer = WriterFactory.OpenAsync(stream, _type, writerOptions);
|
||||
await writer.WriteAllAsync(
|
||||
ORIGINAL_FILES_PATH,
|
||||
"*",
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ZipTypesLevelsWithCrcRatioAsyncTests : ArchiveTests
|
||||
|
||||
// Create zip archive in memory
|
||||
using var zipStream = new MemoryStream();
|
||||
using (var writer = CreateWriterWithLevel(zipStream, compressionType, compressionLevel))
|
||||
using (var writer = CreateWriterWithLevelAsync(zipStream, compressionType, compressionLevel))
|
||||
{
|
||||
await writer.WriteAsync($"file1_{sizeMb}MiB.txt", new MemoryStream(file1Data));
|
||||
await writer.WriteAsync($"data/file2_{sizeMb * 2}MiB.txt", new MemoryStream(file2Data));
|
||||
@@ -129,7 +129,7 @@ public class ZipTypesLevelsWithCrcRatioAsyncTests : ArchiveTests
|
||||
CompressionLevel = compressionLevel,
|
||||
};
|
||||
|
||||
using (var writer = WriterFactory.Open(zipStream, ArchiveType.Zip, writerOptions))
|
||||
using (var writer = WriterFactory.OpenAsync(zipStream, ArchiveType.Zip, writerOptions))
|
||||
{
|
||||
await writer.WriteAsync(
|
||||
$"{compressionType}_level_{compressionLevel}_{sizeMb}MiB.txt",
|
||||
@@ -191,7 +191,7 @@ public class ZipTypesLevelsWithCrcRatioAsyncTests : ArchiveTests
|
||||
|
||||
// Create archive with specified compression and level
|
||||
using var zipStream = new MemoryStream();
|
||||
using (var writer = CreateWriterWithLevel(zipStream, compressionType, compressionLevel))
|
||||
using (var writer = CreateWriterWithLevelAsync(zipStream, compressionType, compressionLevel))
|
||||
{
|
||||
await writer.WriteAsync(
|
||||
$"{compressionType}_{compressionLevel}_{sizeMb}MiB.txt",
|
||||
|
||||
Reference in New Issue
Block a user