2012-07-23 130 views
3

我想壓縮XML樹並將其用作電子郵件附件。帶附件的電子郵件發送成功,但創建的zip文件總是損壞 - 它不是有效的zip文件,但包含二進制數據。爲電子郵件附件壓縮MemoryStream

問題是重建如下,具體參見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 = "[email protected]"; 
    string to = "[email protected]"; 
    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樹的替代視圖,所以我不想要一個完全不同的解決方案。

任何建議爲什麼壓縮文件損壞?

+0

'DeflateStream =郵編File'文件(.zip可以有多種類型的壓縮)的 – user7116 2012-07-23 14:20:24

+0

可能重複[如何使用System.IO.Compression讀/寫ZIP文件?(HTTP:/ /stackoverflow.com/questions/184309/how-to-use-system-io-compression-to-read-write-zip-files) – user7116 2012-07-23 14:24:46

回答

4

您並未創建有效的zip文件,只是創建一個壓縮流並將其寫入具有*.zip擴展名的文件。您應該使用.NET zip庫而不是DeflateStream

您可以使用類似DotNetZip Library

DotNetZip是一個易於使用,快速,免費類庫和工具集 操作zip文件或文件夾。 Zip和Unzip很簡單:使用DotNetZip,用VB編寫的.NET應用程序,C# - 任何.NET語言 - 都可以輕鬆創建,讀取,提取或更新zip文件。適用於單聲道或MS .NET。

如果你有限制,不能使用外部庫,你可以嘗試使用GZipStream並與*.gz延長其將通過常見的壓縮工具,支持添加附件。

作爲將來參考的有用信息,.NET 4.5將終於通過ZipArchive類引入了對zip壓縮歸檔的本地支持。

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()呼叫是必需的。

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); 
} 
0

感謝「尼爾斯R」的回答,我已經創建了一個靜態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; 
    } 
}