3

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サービスアプリケーションの一部であるため、ディスク上にファイルを作成したくありません。また、電子メールメッセージには、xmlツリーのxslt変換された代替ビューも含まれているため、完全に異なるものは必要ありません。解決。

zipファイルが破損している理由はありますか?

4

4 に答える 4

13

これは古い質問だと思いますが、同じものを探していたときに出てきました。

System.IO.Compression.ZipArchive(.NET 4.5以降が必要)を使用して圧縮(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);
}
于 2014-01-03T13:46:12.517 に答える
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()が必要です。

于 2012-07-24T07:48:35.847 に答える
4

有効なzipファイルを作成しているのではなく、圧縮ストリームを作成して、*.zip拡張子が付いたファイルに書き込んでいるだけです。の代わりに.NETzipライブラリを使用する必要がありますDeflateStream

DotNetZipライブラリのようなものを使用できます:

DotNetZipは、zipファイルまたはフォルダーを操作するための、使いやすく、高速で、無料のクラスライブラリおよびツールセットです。Zipと解凍は簡単です。DotNetZipを使用すると、VBで記述された.NETアプリケーション、C#(任意の.NET言語)でzipファイルを簡単に作成、読み取り、抽出、または更新できます。MonoまたはMS.NETの場合。

制約があり、外部ライブラリを使用できない場合は、一般的な圧縮ツールでサポートされるGZipStream拡張子を持つ添付ファイルを使用して追加してみてください。*.gz

将来の参照に役立つ情報として、.NET 4.5は、クラスを介したzipアーカイブのネイティブサポートを最終的に導入します。ZipArchive

于 2012-07-23T14:17:02.810 に答える
0

「Neils.R」の回答のおかげで、添付ファイルを管理し、1Mbを超える場合はそれらを圧縮する静的C#関数を作成しました。これが誰かに役立つことを願っています。

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;
    }
}
于 2017-09-06T09:31:41.007 に答える