更新 : 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 = ;
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(, 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:\MyProgram\MyTempDir";
MagickNET.SetTempDirectory(@"C:\MyProgram\MyTempFiles");
例子
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 = ; if (profile != null)
{
ExifValue orientation = profile.Values.SingleOrDefault(v => v.Tag == ExifTag.Orientation);
if (orientation != null)
{
int orientationInt = Convert.ToInt32(orientation.Value);
if (orientationInt == )
{
image.Rotate();
}
else if (orientationInt == )
{
image.Rotate(-);
}
else if (orientationInt == )
{
image.Rotate();
}
}
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>