我正在尝试压缩XML树并将其用作电子邮件附件。发送带附件的电子邮件成功,但创建的zip文件总是损坏 - 它不是有效的zip文件,但包含二进制数据。
问题重新创建如下,具体见BuildAttachment()
:
static void Main(string[] args)
{
try
{
var report = new XElement("Report",
new XElement("Product",
new XElement("ID", "10000001"),
new XElement("Name", "abcdefghijklm"),
new XElement("Group", "nopqrstuvwxyz")
)
);
var mailMessage = BuildMessage(report);
EmailMessage(mailMessage);
Thread.Sleep(10000);
}
catch (Exception e) { Console.WriteLine(e.Message); }
}
static MailMessage BuildMessage(XElement report)
{
string from = "email1@address.com";
string to = "email2@address.com";
var message = new MailMessage(from, to, "Subject text", "Body text");
var attachment = BuildAttachment(report);
message.Attachments.Add(attachment);
return message;
}
static Attachment BuildAttachment(XElement report)
{
var inStream = new MemoryStream();
report.Save(inStream);
inStream.Position = 0;
var outStream = new MemoryStream();
var compress = new DeflateStream(outStream, CompressionMode.Compress);
inStream.CopyTo(compress);
outStream.Position = 0;
return new Attachment(outStream, "report.zip", "application/zip");
}
static void EmailMessage(MailMessage message)
{
var smtpClient = new SmtpClient("127.0.0.1");
smtpClient.SendCompleted += SendCompletedCallback;
smtpClient.SendAsync(message, null);
}
static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
Console.WriteLine(e.Error.ToString());
}
将问题放在上下文中:它是Windows服务应用程序的一部分,所以我不想在磁盘上创建文件,并且电子邮件消息还包含xslt转换的xml树的备用视图,所以我不想要完全不同的解决方案。
有关zip文件损坏的任何建议吗?
答案 0 :(得分:7)
我知道这是一个古老的问题,但在我搜索时却出现了。
以下是我使用System.IO.Compression.ZipArchive (requires .NET 4.5 or higher)添加压缩(zip)附件的解决方案[基于acraig5075的答案]:
byte[] report = GetSomeReportAsByteArray();
string fileName = "file.txt";
using (MemoryStream memoryStream = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update))
{
ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(fileName);
using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
{
streamWriter.Write(Encoding.Default.GetString(report));
}
}
MemoryStream attachmentStream = new MemoryStream(memoryStream.ToArray());
Attachment attachment = new Attachment(attachmentStream, fileName + ".zip", MediaTypeNames.Application.Zip);
mail.Attachments.Add(attachment);
}
答案 1 :(得分:4)
您没有创建有效的zip文件,只是创建压缩流并将其写入扩展名为*.zip
的文件。您应该使用.NET zip库而不是DeflateStream
。
您可以使用DotNetZip Library:
之类的内容DotNetZip是一个易于使用,快速,免费的类库和工具集 操纵zip文件或文件夹。 Zip和Unzip很简单:有 DotNetZip,用VB编写的.NET应用程序,C# - 任何.NET语言 - 可以轻松创建,读取,提取或更新zip文件。对于Mono或MS .NET。
如果您有约束但无法使用外部库,则可以尝试使用GZipStream
并添加扩展名为*.gz
的附件,这将受到常用压缩工具的支持。
作为将来参考的有用信息,.NET 4.5将最终通过ZipArchive
类引入对zip存档的本机支持。
答案 2 :(得分:4)
为了将来参考,在接受的答案中建议的替代GZipStream
方法,通过如下更改上述代码来生成.gz存档。
static Attachment BuildAttachment(XElement report)
{
var inStream = new MemoryStream();
report.Save(inStream);
inStream.Position = 0;
var outStream = new MemoryStream();
using (var compress = new GZipStream(outStream, CompressionMode.Compress))
{
inStream.CopyTo(compress);
compress.Close();
}
var ms = new MemoryStream(outStream.ToArray());
Attachment attachment = new Attachment(ms, "report.xml.gz", "application/gzip");
return attachment;
}
需要using
阻止和ToArray()
通话。
答案 3 :(得分:0)
感谢" Neils。回答,我创建了一个静态C#函数来管理附件,如果大于1Mb,则将其压缩。希望这对任何人都有帮助。
public static Attachment CreateAttachment(string fileNameAndPath, bool zipIfTooLarge = true, int bytes = 1 << 20)
{
if (!zipIfTooLarge)
{
return new Attachment(fileNameAndPath);
}
var fileInfo = new FileInfo(fileNameAndPath);
// Less than 1Mb just attach as is.
if (fileInfo.Length < bytes)
{
var attachment = new Attachment(fileNameAndPath);
return attachment;
}
byte[] fileBytes = File.ReadAllBytes(fileNameAndPath);
using (var memoryStream = new MemoryStream())
{
string fileName = Path.GetFileName(fileNameAndPath);
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create))
{
ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(fileName, CompressionLevel.Optimal);
using (var streamWriter = new StreamWriter(zipArchiveEntry.Open()))
{
streamWriter.Write(Encoding.Default.GetString(fileBytes));
}
}
var attachmentStream = new MemoryStream(memoryStream.ToArray());
string zipname = $"{Path.GetFileNameWithoutExtension(fileName)}.zip";
var attachment = new Attachment(attachmentStream, zipname, MediaTypeNames.Application.Zip);
return attachment;
}
}