简体   繁体   中英

Zip files and attach them to MailMessage without saving a file

I'm working on a little C# ASP.NET web app that pulls 3 files from my server, creates a zip of those files, and sends the zip file to an e-mail recipient.

The problem I'm having is finding a way to combine those 3 files without creating a zip file on the hard drive of the server. I think I need to use some sort of memorystream or filestream, but I'm in a little beyond my understanding when it comes to merging them into 1 zip file. I've tried SharpZipLib and DotNetZip, but I haven't been able to figure it out.

The reason I don't want the zip saved locally is that there might be a number of users on this app at once, and I don't want to clog up my server machine with those zips. I'm looking for 2 answers, how to zip files without saving the zip as a file, and how to attach that zip to a MailMessage.

Check this example for SharpZipLib: https://github.com/icsharpcode/SharpZipLib/wiki/Zip-Samples#wiki-anchorMemory

using ICSharpCode.SharpZipLib.Zip;

// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {

    MemoryStream outputMemStream = new MemoryStream();
    ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);

    zipStream.SetLevel(3); //0-9, 9 being the highest level of compression

    ZipEntry newEntry = new ZipEntry(zipEntryName);
    newEntry.DateTime = DateTime.Now;

    zipStream.PutNextEntry(newEntry);

    StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
    zipStream.CloseEntry();

    zipStream.IsStreamOwner = false;    // False stops the Close also Closing the underlying stream.
    zipStream.Close();          // Must finish the ZipOutputStream before using outputMemStream.

    outputMemStream.Position = 0;
    return outputMemStream;

    // Alternative outputs:
    // ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
    byte[] byteArrayOut = outputMemStream.ToArray();

    // GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
    byte[] byteArrayOut = outputMemStream.GetBuffer();
    long len = outputMemStream.Length;
}

Try this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM