using System.Text;
namespace MS.Microservice.Core.Text;
///
/// 将输入流中的文本从源编码转换为目标编码,并写入输出流。
/// 从两个流的当前位置开始处理,采用缓冲区分段转换,支持不可定位流。
/// 不自动检测编码,BOM 和无效字符处理遵循指定 Encoding 的配置。
/// 不关闭输入输出流,也不支持原地转换。
/// 转换失败时直接抛出异常,输出流可能包含部分已转换内容。
///
public static class TextEncodingConverter
{
///
/// Converts remaining input using the supplied encodings and fallback policies, leaving both streams open.
/// Configured encoding markers are honored; output may be partial on failure or cancellation.
///
public static async Task ConvertAsync(
Stream source,
Stream destination,
Encoding sourceEncoding,
Encoding targetEncoding,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(destination);
ArgumentNullException.ThrowIfNull(sourceEncoding);
ArgumentNullException.ThrowIfNull(targetEncoding);
if (ReferenceEquals(source, destination))
throw new ArgumentException("Input and output must be different streams.", nameof(destination));
if (!source.CanRead)
throw new ArgumentException("The input stream must be readable.", nameof(source));
if (!destination.CanWrite)
throw new ArgumentException("The output stream must be writable.", nameof(destination));
cancellationToken.ThrowIfCancellationRequested();
using var reader = new StreamReader(source, sourceEncoding,
detectEncodingFromByteOrderMarks: false, bufferSize: 4096, leaveOpen: true);
var writer = new StreamWriter(destination, targetEncoding, bufferSize: 4096, leaveOpen: true);
try
{
var buffer = new char[4096];
int read;
while ((read = await reader.ReadAsync(buffer.AsMemory(), cancellationToken).ConfigureAwait(false)) != 0)
{
await writer.WriteAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false);
}
await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
}
catch
{
try { await writer.DisposeAsync().ConfigureAwait(false); }
catch { /* Preserve the primary conversion or cancellation failure if cleanup also fails. */ }
throw;
}
await writer.DisposeAsync().ConfigureAwait(false);
}
}