我正在调用一个WebAPI,它在ConnectStream中返回PDF。我将ConnectStream写入文件,然后将其读取回内存流,并将其附加到电子邮件中。如何在没有IO开销的情况下完成相同的事情?
System.Net.HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();
System.IO.Stream stream = webResponse.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(stream, Encoding.Default);
string finalPath = System.IO.Path.Combine(outputPath, $"{startDate:yyyy-MM-dd}_{endDate:yyyy-MM-dd}.pdf");
System.IO.Stream fileStream = System.IO.File.OpenWrite(finalPath);
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fileStream, Encoding.Default))
{
sw.Write(reader.ReadToEnd());
sw.Flush();
sw.Close();
}
using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(finalPath)))
{
using (MailMessage mailMessage = new MailMessage())
{
mailMessage.From = new MailAddress("noreply@somedomain.com");
mailMessage.To.Add("someone@somedomain.com");
mailMessage.Attachments.Add(new Attachment(ms, new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf)));
SmtpClient smtpClient = new SmtpClient() { DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.SpecifiedPickupDirectory, PickupDirectoryLocation = outputPath };
smtpClient.Send(mailMessage);
}
}
首先,请求流是单向只读流,不能传递给大多数允许流的方法,因此需要将其读入可以操作的内容:
public byte[] ReadStreamBinary(Stream stream, int bufferSize)
{
using (var ms = new MemoryStream())
{
var buffer = CreateBuffer(bufferSize);
var finished = false;
while (!finished)
{
buffer.Initialize();
var bytes = stream.Read(buffer, 0, buffer.Length);
if (bytes > 0)
{
ms.Write(buffer, 0, bytes);
}
else
{
finished = true;
}
}
return ms.ToArray();
}
}
然后你可以从这个字节数组中创建你的MemoryStream。
由于流的默认内部缓冲区是4k,我几乎总是使用它作为我的缓冲区大小(4096)。在您的情况下,修改方法以直接返回MemoryStream可能更容易。
如果你决定返回流,你需要删除using(这样流就不会被关闭/处理),并返回流指针到开始。
public MemoryStream ReadStreamBinary(Stream stream, int bufferSize)
{
var ms = new MemoryStream();
var buffer = CreateBuffer(bufferSize);
var finished = false;
while (!finished)
{
buffer.Initialize();
var bytes = stream.Read(buffer, 0, buffer.Length);
if (bytes > 0)
{
ms.Write(buffer, 0, bytes);
}
else
{
finished = true;
}
}
ms.Seek(0, SeekOrigin.Begin);
return ms;
}
请记住在调用方法中关闭/处置流。
哦。几乎忘了包括CreateBuffer代码,只需将其放在类的任何地方:
public static Func<int, byte[]> CreateBuffer = x => (byte[])Array.CreateInstance(typeof(byte), x);