是的,您可以使用MimeKitLite 来执行此操作。
使用 MimeKitLite v3.0 完成此任务的最简单方法如下所示:
using (var contentStream = await response.Content.ReadAsStreamAsync ()) {
var header = string.Format ("Content-Type:{0}\r\n\r\n", response.Content.Headers.ContentType);
using (var headerStream = new MemoryStream (Encoding.UTF8.GetBytes (header), false)) {
using (var chainedStream = new ChainedStream ()) {
chained.Add (headerStream);
chained.Add (contentStream);
var reader = new MyMimeReader (chainedStream);
await reader.ReadEntityAsync ();
}
}
}
MyMimeFilter.cs:
public class MyMimeReader : MimeReader
{
static readonly byte[] EmptyInput = new byte[0];
IMimeFilter _decoder;
Stream _fileStream;
string _fileName;
public MyMimeReader (Stream stream) : base (stream, MimeFormat.Entity)
{
}
protected override void OnHeadersBegin (long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
{
// This marks the start of a new MIME entity, so reset our state.
_decoder = DecoderFilter.Create (ContentEncoding.Default);
_fileStream = null;
_fileName = null;
}
protected override void OnHeaderRead (Header header, int beginLineNumber, CancellationToken cancellationToken)
{
switch (header.Id) {
case HeaderId.ContentDisposition:
// If the header is the Content-Disposition header, parse the
// value to get the filename parameter value.
if (ContentDisposition.TryParse (header.RawValue, out var disposition)) {
if (!string.IsNullOrEmpty (disposition.FileName)) {
// Make sure to only use the file name and not a full path.
_fileName = Path.GetFileName (disposition.FileName);
}
}
break;
case HeaderId.ContentTransferEncoding:
// If the header is the Content-Transfer-Encoding header,
// parse the value so that we can decode the content.
_decoder = DecoderFilter.Create (header.Value);
break;
}
}
protected override void OnMimePartBegin (ContentType contentType, long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
{
// If there was a Content-Disposition header, then we'll use that filename.
// Otherwise, check to see if there is a name parameter on the
// Content-Type header and use that. If all else fails, generate a
// new filename.
if (string.IsNullOrEmpty (_fileName)) {
if (string.IsNullOrEmpty (contentType.Name)) {
// Generate a new filename.
_fileName = GenerateRandomFileName ();
} else {
_fileName = Path.GetFileName (contentType.Name);
}
}
}
protected override void OnMimePartContentBegin (long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
{
// Create the file stream that we'll save the content to.
_fileStream = File.Create (_fileName);
}
protected override Task OnMimePartContentReadAsync (byte[] buffer, int startIndex, int count, CancellationToken cancellationToken)
{
int outputIndex, outputLength;
byte[] decoded;
decoded = _decoder.Filter (buffer, startIndex, count, out outputIndex, out outputLength);
await _currentFileStream.WriteAsync (decoded, outputIndex, outputLength, cancellationToken);
}
protected override Task OnMimePartContentEndAsync (long beginOffset, int beginLineNumber, long endOffset, int lines, NewLineFormat? newLineFormat, CancellationToken cancellationToken)
{
int outputIndex, outputLength;
byte[] decoded;
decoded = _decoder.Flush (EmptyInput, 0, 0, out outputIndex, out outputLength);
if (outputLength > 0)
await _fileStream.WriteAsync (decoded, outputIndex, outputLength, cancellationToken);
await _fileStream.FlushAsync (cancellationToken);
_fileStream.Dispose ();
_fileStream = null;
}
}