zoukankan      html  css  js  c++  java
  • Asp.net core 学习笔记 ( upload/download files 文件上传与下载 )

    更新: 2021-06-14

    改用 image sharp 来处理图片了.
    https://www.cnblogs.com/keatkeat/p/14882828.html

    更新: 2021-06-01

    https://medium.com/@harrisonifeanyichukwu/why-you-should-leave-the-ua-to-set-the-multipart-content-type-header-6c8400cbc90f

    最好不要自己 set Content-Type multipart/form-data

    因为它需要一个 unique 来做分割线, 而我们通常会忘记掉,然后后端就 error 了, 其实游览器很聪明的 它会自己 handle.

    更新 :  2018-01-22 

    之前漏掉了一个 image 优化, 就是 progressive jpg 

    refer : 

    http://techslides.com/demos/progressive-test.html (online test)

    http://magick.codeplex.com/discussions/450804 (Magick)

    https://www.imgonline.com.ua/eng/make-jpeg-progressive-without-compression-result.php (online convert)

    https://developers.google.com/speed/docs/insights/OptimizeImages (google 优化图片指南)

    image.Settings.SetDefine(MagickFormat.Jpeg, "sampling-factor", "4:2:0");
    image.Format = MagickFormat.Pjpeg; // 转换成 progressive jpg 
    image.Strip(); //这句会把图片的所有 EXIF 洗掉
    image.Quality = 85;

    2017-09-25 

    refer : https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads

    https://www.codeproject.com/Articles/1203408/Upload-Download-Files-in-ASP-NET-Core

    这里只说说小文件上传. 

    先看看前端 js 代码 

    <input id="inputFile" type="file" />
    <script>
        document.getElementById('inputFile').addEventListener('change', (e) => {        
            let files = e.target.files;        
            let formData = new FormData();
            formData.append("file", files[0]);
            let http = new XMLHttpRequest();
            http.open('POST', '/upload-file', true);
            http.send(formData); 
        }, false); 
    </script>

    如果要上传多个文件就 append 多几个就是了 

    c# 

    public class UploadFileData
    {
        public IFormFile file { get; set; }
    }
    
    [Area("Web")]
    public class UploadController : Controller
    {
        public UploadController(
                IHostingEnvironment environment
        )
        {
            this.environment = environment;
        }
    
        private IHostingEnvironment environment { get; set; }
            
        [HttpPost("upload-file")]
        public async Task<IActionResult> uploadFile(UploadFileData data)
        {
            var allFiles = Request.Form.Files; // 多文件的话可以直接从 form 拿到完, 或则设置成 List<IFormFile> 就可以了
            var root = environment.WebRootPath;
            var extension = Path.GetExtension(data.file.FileName);
            var guid = Guid.NewGuid().ToString();
            var fullPath = $@"{root}images{guid + extension}";
            using (FileStream stream = new FileStream(fullPath, FileMode.Create))
            {
                await data.file.CopyToAsync(stream);
            } 
            return Ok();
        }
        [Route("upload")]
        public async Task<IActionResult> Index()
        {
            return View();
        }
    }

    上面的是最简单的版本,创建 file 然后把 upload file stream 写入 

    如果是想直接使用 stream 也是可以 

    using (var memoryStream = new MemoryStream())
    {
        await model.file.CopyToAsync(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);
        new FileExtensionContentTypeProvider().TryGetContentType(model.file.FileName, out string contentType);
    
        await EmailService.SendAsync(
            recipients: BusinessConfig.contactEmailHandler,
            subject: "Contact form from website",
            templatePath: "~/Email/Contact/Index.cshtml",
            model: model,
            attachs: new List<Attachment> { new Attachment(memoryStream, model.file.FileName, contentType ?? "application/octet-stream") }
        );
    }

    需要注意的是写入 stream 后, 如果要读取 stream 记得, Seek 一下. 

    还有一个常用的场景是, 上传图片要做 EXIF 处理. 

    可以用 Magick.NET 目前支持 core, 不过呢, 好像只支持 window 场景. 如果你不是 windows 可能要在等等或则用其它插件.

    Magick 需要设置, 参考 : https://magick.codeplex.com/documentation

    MagickAnyCPU.CacheDirectory = @"C:MyProgramMyTempDir";
    MagickNET.SetTempDirectory(@"C:MyProgramMyTempFiles");
    例子
    using (var stream = data.file.OpenReadStream())
    using (MagickImage image = new MagickImage(stream))
    {
        ExifProfile profile = image.GetExifProfile();
        image.Settings.SetDefine(MagickFormat.Jpeg, "sampling-factor", "4:2:0");
        image.Strip(); //这句会把图片的所有 EXIF 洗掉
        image.Quality = 85;
    
        if (profile != null)
        {
            ExifValue orientation = profile.Values.SingleOrDefault(v => v.Tag == ExifTag.Orientation);
            if (orientation != null)
            {
                int orientationInt = Convert.ToInt32(orientation.Value);
                if (orientationInt == 6)
                {
                    image.Rotate(90);
                }
                else if (orientationInt == 8)
                {
                    image.Rotate(-90);
                }
                else if (orientationInt == 8)
                {
                    image.Rotate(180);
                }
            }
            image.Write(fullPath);
        }
        else
        {
            image.Write(fullPath);
        }
    }

    很简单吧.

    再来一个 zip 的 

    using (var stream = data.file.OpenReadStream())
    using (var compressedFileStream = new FileStream($@"{root}images{guid}.zip", FileMode.Create))
    using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false))
    {
        var zipEntry = zipArchive.CreateEntry(data.file.FileName);
        using (var zipEntryStream = zipEntry.Open())
        {
            stream.CopyTo(zipEntryStream);
        }
    }

    core 支持 ZipArchive 哦

    下载也很容易 

    public UploadController(
            IHostingEnvironment environment,
            IContentTypeProvider contentTypeProvider
    )
    {
        this.environment = environment;
        this.contentTypeProvider = contentTypeProvider;
    }
    
    private IHostingEnvironment environment { get; set; }
    private IContentTypeProvider contentTypeProvider { get; set; }
            
    [HttpGet("download-file")]
    public FileResult downloadFile(string name, string display)
    {
        string contentType;
        contentTypeProvider.TryGetContentType(name, out contentType);
        HttpContext.Response.ContentType = contentType;
        string path = environment.WebRootPath + @"images" + name; // 注意哦, 不要像我这样直接使用客户端的值来拼接 path, 危险的 
        FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes(path), contentType)
        {
            FileDownloadName = display
        };
       // return File("~/excels/report.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "report.xlsx"); // 返回 File + 路径也是可以, 这个路径是从 wwwroot 走起
       // return File(await System.IO.File.ReadAllBytesAsync(path), same...) // 或则我们可以直接返回 byte[], 任意从哪里获取都可以.
    return result; }

    html

    <a href="/download-file?name=123.jpg&display=aaa.jpg" download  >download</a>
  • 相关阅读:
    知社 —— 第 4 次站立式会议(04-28)
    知社 —— 第 3 次站立式会议(04-27)
    知社 —— 第 2 次站立式会议(04-26)
    知社 —— 第 1 次站立式会议(04-25)
    团队代码规范、冲刺任务与计划
    团队作业第四次 — 项目系统设计与数据库设计
    团队作业第三次 — 项目需求分析
    第01组 Alpha冲刺(5/6)
    2019 SDN上机第4次作业
    2019 SDN阅读作业
  • 原文地址:https://www.cnblogs.com/keatkeat/p/7594496.html
Copyright © 2011-2022 走看看