Selaa lähdekoodia

增加池化流

懒得勤快 2 vuotta sitten
vanhempi
sitoutus
4511e14500

+ 7 - 4
Masuit.Tools.Abstractions/Extensions/BaseType/StreamExtensions.cs

@@ -1,4 +1,5 @@
-using System;
+using Masuit.Tools.Systems;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
@@ -20,10 +21,12 @@ namespace Masuit.Tools
         /// </summary>
         /// <param name="stream"></param>
         /// <returns></returns>
-        public static MemoryStream SaveAsMemoryStream(this Stream stream)
+        public static PooledMemoryStream SaveAsMemoryStream(this Stream stream)
         {
-            stream.Position = 0;
-            return new MemoryStream(stream.ToArray());
+            stream.Seek(0, SeekOrigin.Begin);
+            var ms = new PooledMemoryStream();
+            stream.CopyTo(ms);
+            return ms;
         }
 
         /// <summary>

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileExt.cs

@@ -49,7 +49,7 @@ namespace Masuit.Tools.Files
         /// </summary>
         /// <param name="ms"></param>
         /// <param name="filename"></param>
-        public static void SaveFile(this MemoryStream ms, string filename)
+        public static void SaveFile(this Stream ms, string filename)
         {
             using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
             byte[] buffer = ms.ToArray(); // 转化为byte格式存储

+ 2 - 2
Masuit.Tools.Abstractions/Files/ISevenZipCompressor.cs

@@ -43,7 +43,7 @@ namespace Masuit.Tools.Files
         /// <param name="rootdir"></param>
         /// <param name="archiveType"></param>
         /// <returns>文件流</returns>
-        MemoryStream ZipStream(IEnumerable<string> files, string rootdir = "", ArchiveType archiveType = ArchiveType.Zip);
+        PooledMemoryStream ZipStream(IEnumerable<string> files, string rootdir = "", ArchiveType archiveType = ArchiveType.Zip);
 
         /// <summary>
         /// 将多个文件压缩到一个文件流中,可保存为zip文件,方便于web方式下载
@@ -52,6 +52,6 @@ namespace Masuit.Tools.Files
         /// <param name="archiveType"></param>
         /// <param name="disposeAllStreams">是否需要释放所有流</param>
         /// <returns>文件流</returns>
-        MemoryStream ZipStream(DisposableDictionary<string, Stream> streams, ArchiveType archiveType = ArchiveType.Zip, bool disposeAllStreams = false);
+        PooledMemoryStream ZipStream(DisposableDictionary<string, Stream> streams, ArchiveType archiveType = ArchiveType.Zip, bool disposeAllStreams = false);
     }
 }

+ 6 - 6
Masuit.Tools.Abstractions/Files/SevenZipCompressor.cs

@@ -1,4 +1,5 @@
-using SharpCompress.Archives;
+using Masuit.Tools.Systems;
+using SharpCompress.Archives;
 using SharpCompress.Common;
 using SharpCompress.Writers;
 using System;
@@ -10,7 +11,6 @@ using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
 using System.Web;
-using Masuit.Tools.Systems;
 
 namespace Masuit.Tools.Files
 {
@@ -37,10 +37,10 @@ namespace Masuit.Tools.Files
         /// <param name="rootdir"></param>
         /// <param name="archiveType"></param>
         /// <returns>文件流</returns>
-        public MemoryStream ZipStream(IEnumerable<string> files, string rootdir = "", ArchiveType archiveType = ArchiveType.Zip)
+        public PooledMemoryStream ZipStream(IEnumerable<string> files, string rootdir = "", ArchiveType archiveType = ArchiveType.Zip)
         {
             using var archive = CreateZipArchive(files, rootdir, archiveType);
-            var ms = new MemoryStream();
+            var ms = new PooledMemoryStream();
             archive.SaveTo(ms, new WriterOptions(CompressionType.LZMA)
             {
                 LeaveStreamOpen = true,
@@ -59,7 +59,7 @@ namespace Masuit.Tools.Files
         /// <param name="archiveType"></param>
         /// <param name="disposeAllStreams">是否需要释放所有流</param>
         /// <returns>文件流</returns>
-        public MemoryStream ZipStream(DisposableDictionary<string, Stream> streams, ArchiveType archiveType = ArchiveType.Zip, bool disposeAllStreams = false)
+        public PooledMemoryStream ZipStream(DisposableDictionary<string, Stream> streams, ArchiveType archiveType = ArchiveType.Zip, bool disposeAllStreams = false)
         {
             using var archive = ArchiveFactory.Create(archiveType);
             foreach (var pair in streams)
@@ -67,7 +67,7 @@ namespace Masuit.Tools.Files
                 archive.AddEntry(pair.Key, pair.Value, true);
             }
 
-            var ms = new MemoryStream();
+            var ms = new PooledMemoryStream();
             archive.SaveTo(ms, new WriterOptions(CompressionType.LZMA)
             {
                 LeaveStreamOpen = true,

+ 3 - 3
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -3,7 +3,7 @@
         <TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6;net7</TargetFrameworks>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>2.5.8.3</Version>
+        <Version>2.5.9-beta</Version>
         <Authors>懒得勤快</Authors>
         <Description>Masuit.Tools基础公共库,包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。</Description>
         <Copyright>懒得勤快,长空X</Copyright>
@@ -16,9 +16,9 @@
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
         <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
-        <FileVersion>$(Version)</FileVersion>
+        <FileVersion>2.5.9</FileVersion>
         <Company>masuit.org</Company>
-        <AssemblyVersion>$(Version)</AssemblyVersion>
+        <AssemblyVersion>2.5.9</AssemblyVersion>
         <PackageLicenseUrl>https://github.com/ldqk/Masuit.Tools/blob/master/LICENSE</PackageLicenseUrl>
         <EmbedUntrackedSources>true</EmbedUntrackedSources>
         <IncludeSymbols>true</IncludeSymbols>

+ 4 - 3
Masuit.Tools.Abstractions/Media/ImageDetectExt.cs

@@ -1,4 +1,5 @@
-using SixLabors.ImageSharp;
+using Masuit.Tools.Systems;
+using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.Formats.Bmp;
 using SixLabors.ImageSharp.Formats.Gif;
 using SixLabors.ImageSharp.Formats.Jpeg;
@@ -111,8 +112,8 @@ public static class ImageDetectExt
         {
             try
             {
-                var ms = new MemoryStream(img);
-                var msOut = new MemoryStream();
+                using var ms = new PooledMemoryStream(img);
+                using var msOut = new PooledMemoryStream();
                 const int bufferSize = 4096;
                 var buffer = new byte[bufferSize];
                 using var z = new GZipStream(ms, CompressionMode.Decompress);

+ 3 - 3
Masuit.Tools.Abstractions/Media/ImageUtilities.cs

@@ -1,9 +1,9 @@
-using System;
-using System.IO;
+using Masuit.Tools.Systems;
 using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.PixelFormats;
 using SixLabors.ImageSharp.Processing;
 using SixLabors.ImageSharp.Processing.Processors.Transforms;
+using System;
 
 namespace Masuit.Tools.Media
 {
@@ -337,7 +337,7 @@ namespace Masuit.Tools.Media
         {
             string strbase64 = source.Substring(source.IndexOf(',') + 1).Trim('\0');
             byte[] arr = Convert.FromBase64String(strbase64);
-            using var ms = new MemoryStream(arr);
+            var ms = new PooledMemoryStream(arr);
             return Image.Load(ms);
         }
     }

+ 159 - 158
Masuit.Tools.Abstractions/Media/ImageWatermarker.cs

@@ -1,4 +1,5 @@
-using SixLabors.Fonts;
+using Masuit.Tools.Systems;
+using SixLabors.Fonts;
 using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.Drawing.Processing;
 using SixLabors.ImageSharp.Processing;
@@ -8,161 +9,161 @@ using System.IO;
 
 namespace Masuit.Tools.Media
 {
-	public class ImageWatermarker
-	{
-		/// <summary>
-		/// 是否跳过小缩略图
-		/// </summary>
-		public bool SkipWatermarkForSmallImages { get; set; }
-
-		/// <summary>
-		/// 小图像素大小
-		/// </summary>
-		public int SmallImagePixelsThreshold { get; set; }
-
-		private readonly Stream _stream;
-
-		public ImageWatermarker(Stream originStream)
-		{
-			_stream = originStream;
-		}
-
-		public MemoryStream AddWatermark(string watermarkText, string ttfFontPath, int fontSize, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10)
-		{
-			var fonts = new FontCollection();
-			var fontFamily = fonts.Add(ttfFontPath); //字体的路径(电脑自带字体库,去copy出来)
-			var font = new Font(fontFamily, fontSize, FontStyle.Bold);
-			return AddWatermark(watermarkText, font, color, watermarkPosition, textPadding);
-		}
-
-		/// <summary>
-		/// 添加水印
-		/// </summary>
-		/// <param name="watermarkText">水印文字</param>
-		/// <param name="color">水印颜色</param>
-		/// <param name="watermarkPosition">水印位置</param>
-		/// <param name="textPadding">边距</param>
-		/// <param name="font">字体</param>
-		/// <returns></returns>
-		public MemoryStream AddWatermark(string watermarkText, Font font, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10)
-		{
-			using var img = Image.Load(_stream);
-			var textMeasure = TextMeasurer.Measure(watermarkText, new TextOptions(font));
-			if (SkipWatermarkForSmallImages && (img.Height < Math.Sqrt(SmallImagePixelsThreshold) || img.Width < Math.Sqrt(SmallImagePixelsThreshold) || img.Width <= textMeasure.Width))
-			{
-				return _stream as MemoryStream ?? _stream.SaveAsMemoryStream();
-			}
-
-			if (img.Width / font.Size > 50)
-			{
-				font = font.Family.CreateFont(img.Width * 1f / 50);
-			}
-
-			float x, y;
-			textPadding += (img.Width - 1000) / 100;
-			switch (watermarkPosition)
-			{
-				case WatermarkPosition.TopRight:
-					x = img.Width - textMeasure.Width - textPadding;
-					y = textPadding;
-					break;
-
-				case WatermarkPosition.BottomLeft:
-					x = textPadding;
-					y = img.Height - textMeasure.Height - textPadding;
-					break;
-
-				case WatermarkPosition.BottomRight:
-					x = img.Width - textMeasure.Width - textPadding;
-					y = img.Height - textMeasure.Height - textPadding;
-					break;
-
-				case WatermarkPosition.Center:
-					x = (img.Width - textMeasure.Width) / 2;
-					y = (img.Height - textMeasure.Height) / 2;
-					break;
-
-				default:
-					x = textPadding;
-					y = textPadding;
-					break;
-			}
-
-			img.Mutate(c => c.DrawText(watermarkText, font, color, new PointF(x, y)));
-			var ms = new MemoryStream();
-			img.SaveAsWebp(ms);
-			ms.Position = 0;
-			return ms;
-		}
-
-		/// <summary>
-		/// 添加水印
-		/// </summary>
-		/// <param name="watermarkImage">水印图片</param>
-		/// <param name="opacity">水印图片</param>
-		/// <param name="watermarkPosition">水印位置</param>
-		/// <param name="padding">水印边距</param>
-		/// <returns></returns>
-		public MemoryStream AddWatermark(Stream watermarkImage, float opacity = 1f, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int padding = 20)
-		{
-			using var img = Image.Load(_stream);
-			var height = img.Height;
-			var width = img.Width;
-			if (SkipWatermarkForSmallImages && (height < Math.Sqrt(SmallImagePixelsThreshold) || width < Math.Sqrt(SmallImagePixelsThreshold)))
-			{
-				return _stream as MemoryStream ?? _stream.SaveAsMemoryStream();
-			}
-
-			var watermark = Image.Load(watermarkImage);
-			watermark.Mutate(c => c.Resize(new ResizeOptions()
-			{
-				Size = new Size
-				{
-					Width = width / 10,
-					Height = height / 10,
-				},
-				Mode = ResizeMode.Pad,
-				Sampler = new BicubicResampler()
-			}));
-			int x, y;
-			padding += (width - 1000) / 100;
-			switch (watermarkPosition)
-			{
-				case WatermarkPosition.TopRight:
-					x = width - watermark.Width - padding;
-					y = padding;
-					break;
-
-				case WatermarkPosition.BottomLeft:
-					x = padding;
-					y = height - watermark.Height - padding;
-					break;
-
-				case WatermarkPosition.BottomRight:
-					x = width - watermark.Width - padding;
-					y = height - watermark.Height - padding;
-					break;
-
-				case WatermarkPosition.Center:
-					x = (img.Width - watermark.Width) / 2;
-					y = (img.Height - watermark.Height) / 2;
-					break;
-
-				default:
-					x = padding;
-					y = padding;
-					break;
-			}
-
-			img.Mutate(c =>
-			{
-				c.DrawImage(watermark, new Point(x, y), opacity);
-				watermark.Dispose();
-			});
-			var ms = new MemoryStream();
-			img.SaveAsWebp(ms);
-			ms.Position = 0;
-			return ms;
-		}
-	}
+    public class ImageWatermarker
+    {
+        /// <summary>
+        /// 是否跳过小缩略图
+        /// </summary>
+        public bool SkipWatermarkForSmallImages { get; set; }
+
+        /// <summary>
+        /// 小图像素大小
+        /// </summary>
+        public int SmallImagePixelsThreshold { get; set; }
+
+        private readonly Stream _stream;
+
+        public ImageWatermarker(Stream originStream)
+        {
+            _stream = originStream;
+        }
+
+        public PooledMemoryStream AddWatermark(string watermarkText, string ttfFontPath, int fontSize, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10)
+        {
+            var fonts = new FontCollection();
+            var fontFamily = fonts.Add(ttfFontPath); //字体的路径(电脑自带字体库,去copy出来)
+            var font = new Font(fontFamily, fontSize, FontStyle.Bold);
+            return AddWatermark(watermarkText, font, color, watermarkPosition, textPadding);
+        }
+
+        /// <summary>
+        /// 添加水印
+        /// </summary>
+        /// <param name="watermarkText">水印文字</param>
+        /// <param name="color">水印颜色</param>
+        /// <param name="watermarkPosition">水印位置</param>
+        /// <param name="textPadding">边距</param>
+        /// <param name="font">字体</param>
+        /// <returns></returns>
+        public PooledMemoryStream AddWatermark(string watermarkText, Font font, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10)
+        {
+            using var img = Image.Load(_stream);
+            var textMeasure = TextMeasurer.Measure(watermarkText, new TextOptions(font));
+            if (SkipWatermarkForSmallImages && (img.Height < Math.Sqrt(SmallImagePixelsThreshold) || img.Width < Math.Sqrt(SmallImagePixelsThreshold) || img.Width <= textMeasure.Width))
+            {
+                return _stream as PooledMemoryStream ?? _stream.SaveAsMemoryStream();
+            }
+
+            if (img.Width / font.Size > 50)
+            {
+                font = font.Family.CreateFont(img.Width * 1f / 50);
+            }
+
+            float x, y;
+            textPadding += (img.Width - 1000) / 100;
+            switch (watermarkPosition)
+            {
+                case WatermarkPosition.TopRight:
+                    x = img.Width - textMeasure.Width - textPadding;
+                    y = textPadding;
+                    break;
+
+                case WatermarkPosition.BottomLeft:
+                    x = textPadding;
+                    y = img.Height - textMeasure.Height - textPadding;
+                    break;
+
+                case WatermarkPosition.BottomRight:
+                    x = img.Width - textMeasure.Width - textPadding;
+                    y = img.Height - textMeasure.Height - textPadding;
+                    break;
+
+                case WatermarkPosition.Center:
+                    x = (img.Width - textMeasure.Width) / 2;
+                    y = (img.Height - textMeasure.Height) / 2;
+                    break;
+
+                default:
+                    x = textPadding;
+                    y = textPadding;
+                    break;
+            }
+
+            img.Mutate(c => c.DrawText(watermarkText, font, color, new PointF(x, y)));
+            var ms = new PooledMemoryStream();
+            img.SaveAsWebp(ms);
+            ms.Position = 0;
+            return ms;
+        }
+
+        /// <summary>
+        /// 添加水印
+        /// </summary>
+        /// <param name="watermarkImage">水印图片</param>
+        /// <param name="opacity">水印图片</param>
+        /// <param name="watermarkPosition">水印位置</param>
+        /// <param name="padding">水印边距</param>
+        /// <returns></returns>
+        public PooledMemoryStream AddWatermark(Stream watermarkImage, float opacity = 1f, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int padding = 20)
+        {
+            using var img = Image.Load(_stream);
+            var height = img.Height;
+            var width = img.Width;
+            if (SkipWatermarkForSmallImages && (height < Math.Sqrt(SmallImagePixelsThreshold) || width < Math.Sqrt(SmallImagePixelsThreshold)))
+            {
+                return _stream as PooledMemoryStream ?? _stream.SaveAsMemoryStream();
+            }
+
+            var watermark = Image.Load(watermarkImage);
+            watermark.Mutate(c => c.Resize(new ResizeOptions()
+            {
+                Size = new Size
+                {
+                    Width = width / 10,
+                    Height = height / 10,
+                },
+                Mode = ResizeMode.Pad,
+                Sampler = new BicubicResampler()
+            }));
+            int x, y;
+            padding += (width - 1000) / 100;
+            switch (watermarkPosition)
+            {
+                case WatermarkPosition.TopRight:
+                    x = width - watermark.Width - padding;
+                    y = padding;
+                    break;
+
+                case WatermarkPosition.BottomLeft:
+                    x = padding;
+                    y = height - watermark.Height - padding;
+                    break;
+
+                case WatermarkPosition.BottomRight:
+                    x = width - watermark.Width - padding;
+                    y = height - watermark.Height - padding;
+                    break;
+
+                case WatermarkPosition.Center:
+                    x = (img.Width - watermark.Width) / 2;
+                    y = (img.Height - watermark.Height) / 2;
+                    break;
+
+                default:
+                    x = padding;
+                    y = padding;
+                    break;
+            }
+
+            img.Mutate(c =>
+            {
+                c.DrawImage(watermark, new Point(x, y), opacity);
+                watermark.Dispose();
+            });
+            var ms = new PooledMemoryStream();
+            img.SaveAsWebp(ms);
+            ms.Position = 0;
+            return ms;
+        }
+    }
 }

+ 14 - 13
Masuit.Tools.Abstractions/Security/Encrypt.cs

@@ -1,4 +1,5 @@
-using System;
+using Masuit.Tools.Systems;
+using System;
 using System.IO;
 using System.Security.Cryptography;
 using System.Text;
@@ -32,7 +33,7 @@ namespace Masuit.Tools.Security
             byte[] inputByteArray = Encoding.Default.GetBytes(strText);
             des.Key = Encoding.ASCII.GetBytes(strEncrKey.Substring(0, 8));
             des.IV = Encoding.ASCII.GetBytes(strEncrKey.Substring(0, 8));
-            MemoryStream ms = new MemoryStream();
+            using var ms = new PooledMemoryStream();
             using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
             cs.Write(inputByteArray, 0, inputByteArray.Length);
             cs.FlushFinalBlock();
@@ -59,7 +60,7 @@ namespace Masuit.Tools.Security
             byte[] inputByteArray = Encoding.Default.GetBytes(strText);
             des.Key = desKey;
             des.IV = desIV;
-            MemoryStream ms = new MemoryStream();
+            using var ms = new PooledMemoryStream();
             using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
             cs.Write(inputByteArray, 0, inputByteArray.Length);
             cs.FlushFinalBlock();
@@ -203,7 +204,7 @@ namespace Masuit.Tools.Security
                 throw new Exception("密钥长度无效,密钥必须是8位!");
             }
 
-            var ms = new MemoryStream();
+            using var ms = new PooledMemoryStream();
             using var des = DES.Create();
             var inputByteArray = new byte[pToDecrypt.Length / 2];
             for (int x = 0; x < pToDecrypt.Length / 2; x++)
@@ -230,7 +231,7 @@ namespace Masuit.Tools.Security
         /// <returns>解密后的数据</returns>
         public static string DesDecrypt(this string pToDecrypt, byte[] desKey, byte[] desIV)
         {
-            var ms = new MemoryStream();
+            using var ms = new PooledMemoryStream();
             using var des = DES.Create();
             var inputByteArray = new byte[pToDecrypt.Length / 2];
             for (int x = 0; x < pToDecrypt.Length / 2; x++)
@@ -874,7 +875,7 @@ namespace Masuit.Tools.Security
             tmpFileStream.Close();
             //定义基本的加密转换运算
             using var encryptor = _rc2Csp.CreateEncryptor(_key, _iv);
-            var msEncrypt = new MemoryStream();
+            using var msEncrypt = new PooledMemoryStream();
             //在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
             using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
             //将要加密的文本转换成UTF-16 编码,保存在tmp数组。
@@ -922,7 +923,7 @@ namespace Masuit.Tools.Security
 
             using var tmpFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 1024, true);
             using var decryptor = _rc2Csp.CreateDecryptor(_key, _iv);
-            var msDecrypt = new MemoryStream();
+            using var msDecrypt = new PooledMemoryStream();
             using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
             var index = new byte[10261];
             tmpFileStream.Read(index, 0, 10261);
@@ -949,7 +950,7 @@ namespace Masuit.Tools.Security
         {
             using var tmpFileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 1024, true);
             using var encryptor = _rc2Csp.CreateEncryptor(_key, _iv);
-            var msEncrypt = new MemoryStream();
+            using var msEncrypt = new PooledMemoryStream();
             using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
             var tmp = _textConverter.GetBytes(toEncryptText);
             csEncrypt.Write(tmp, 0, tmp.Length);
@@ -971,7 +972,7 @@ namespace Masuit.Tools.Security
         {
             using var tmpFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 1024, true);
             using var decryptor = _rc2Csp.CreateDecryptor(_key, _iv);
-            var msDecrypt = new MemoryStream();
+            using var msDecrypt = new PooledMemoryStream();
             using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
             var tmp = new byte[tmpFileStream.Length];
             tmpFileStream.Read(tmp, 0, tmp.Length);
@@ -1011,7 +1012,7 @@ namespace Masuit.Tools.Security
 
             //定义基本的加密转换运算
             using var encryptor = _rc2Csp.CreateEncryptor(Key, IV);
-            var msEncrypt = new MemoryStream();
+            using var msEncrypt = new PooledMemoryStream();
             //在此加密转换流中,加密将从csEncrypt,加密后,结果在msEncrypt流中。
             using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
             var tmp = _textConverter.GetBytes(toEncryptText);
@@ -1063,7 +1064,7 @@ namespace Masuit.Tools.Security
 
             using var tmpFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 1024, true);
             using var decryptor = _rc2Csp.CreateDecryptor(key, iv);
-            var msDecrypt = new MemoryStream();
+            using var msDecrypt = new PooledMemoryStream();
             using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
             var index = new byte[10261];
             tmpFileStream.Read(index, 0, 10261);
@@ -1092,7 +1093,7 @@ namespace Masuit.Tools.Security
         {
             using var tmpFileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 1024, true);
             using var encryptor = _rc2Csp.CreateEncryptor(key, iv);
-            var msEncrypt = new MemoryStream();
+            using var msEncrypt = new PooledMemoryStream();
             using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
             var tmp = _textConverter.GetBytes(toEncryptText);
             csEncrypt.Write(tmp, 0, tmp.Length);
@@ -1117,7 +1118,7 @@ namespace Masuit.Tools.Security
         {
             using var tmpFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 1024, true);
             using var decryptor = _rc2Csp.CreateDecryptor(key, iv);
-            var msDecrypt = new MemoryStream();
+            using var msDecrypt = new PooledMemoryStream();
             using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
             var tmp = new byte[tmpFileStream.Length];
             tmpFileStream.Read(tmp, 0, tmp.Length);

+ 6 - 6
Masuit.Tools.Abstractions/Security/RSA.cs

@@ -1,5 +1,5 @@
-using System;
-using System.IO;
+using Masuit.Tools.Systems;
+using System;
 using System.Security.Cryptography;
 using System.Text;
 
@@ -62,8 +62,8 @@ namespace Masuit.Tools.Security
                 return RSAObject.Encrypt(data, false);
             }
 
-            using var dataStream = new MemoryStream(data);
-            using var enStream = new MemoryStream();
+            using var dataStream = new PooledMemoryStream(data);
+            using var enStream = new PooledMemoryStream();
             var buffer = new byte[blockLen];
             int len = dataStream.Read(buffer, 0, blockLen);
 
@@ -120,8 +120,8 @@ namespace Masuit.Tools.Security
                     return RSAObject.Decrypt(data, false);
                 }
 
-                using var dataStream = new MemoryStream(data);
-                using var deStream = new MemoryStream();
+                using var dataStream = new PooledMemoryStream(data);
+                using var deStream = new PooledMemoryStream();
                 byte[] buffer = new byte[blockLen];
                 int len = dataStream.Read(buffer, 0, blockLen);
 

+ 4 - 3
Masuit.Tools.Abstractions/Security/RsaPem.cs

@@ -1,4 +1,5 @@
-using System;
+using Masuit.Tools.Systems;
+using System;
 using System.IO;
 using System.Linq;
 using System.Numerics;
@@ -431,7 +432,7 @@ namespace Masuit.Tools.Security
         /// </summary>
         public string ToPEM(bool convertToPublic, bool usePKCS8)
         {
-            var ms = new MemoryStream();
+            var ms = new PooledMemoryStream();
             //写入一个长度字节码
             Action<int> writeLenByte = len =>
             {
@@ -478,7 +479,7 @@ namespace Masuit.Tools.Security
 
                 return ms.ToArray();
             };
-            Action<MemoryStream, byte[]> writeAll = (stream, byts) =>
+            Action<Stream, byte[]> writeAll = (stream, byts) =>
             {
                 stream.Write(byts, 0, byts.Length);
             };

+ 2 - 2
Masuit.Tools.Abstractions/Strings/ValidateCode.cs

@@ -7,11 +7,11 @@ using Microsoft.AspNetCore.Http;
 #endif
 
 using System;
-using System.IO;
 using System.Linq;
 using System.Security.Cryptography;
 using System.Text;
 using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Systems;
 using SixLabors.Fonts;
 using SixLabors.ImageSharp;
 using SixLabors.ImageSharp.PixelFormats;
@@ -103,7 +103,7 @@ namespace Masuit.Tools.Strings
             }
 
             //保存图片数据
-            using MemoryStream stream = new MemoryStream();
+            using var stream = new PooledMemoryStream();
             image.Save(stream, WebpFormat.Instance);
 
             //输出图片流

+ 274 - 0
Masuit.Tools.Abstractions/Systems/LargeMemoryStream.cs

@@ -0,0 +1,274 @@
+using System;
+using System.Buffers;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 大型内存流,最大可支持1TB数据
+/// </summary>
+public class LargeMemoryStream : Stream
+{
+    /// <summary>
+    /// 终结器
+    /// </summary>
+    ~LargeMemoryStream()
+    {
+        Dispose(true);
+    }
+
+    private const int PageSize = 1024000000;
+    private const int AllocStep = 1024;
+
+    private byte[][] _streamBuffers;
+
+    private int _pageCount = 0;
+    private long _allocatedBytes = 0;
+
+    private long _position = 0;
+    private long _length = 0;
+    private bool _isDisposed;
+
+    private int GetPageCount(long length)
+    {
+        int pageCount = (int)(length / PageSize) + 1;
+
+        if ((length % PageSize) == 0)
+            pageCount--;
+
+        return pageCount;
+    }
+
+    private void ExtendPages()
+    {
+        if (_streamBuffers == null)
+        {
+            _streamBuffers = new byte[AllocStep][];
+        }
+        else
+        {
+            var streamBuffers = new byte[_streamBuffers.Length + AllocStep][];
+            Array.Copy(_streamBuffers, streamBuffers, _streamBuffers.Length);
+            _streamBuffers = streamBuffers;
+        }
+
+        _pageCount = _streamBuffers.Length;
+    }
+
+    private void AllocSpaceIfNeeded(long value)
+    {
+        if (value < 0)
+            throw new InvalidOperationException("AllocSpaceIfNeeded < 0");
+
+        if (value == 0)
+            return;
+
+        int currentPageCount = GetPageCount(_allocatedBytes);
+        int neededPageCount = GetPageCount(value);
+
+        while (currentPageCount < neededPageCount)
+        {
+            if (currentPageCount == _pageCount)
+                ExtendPages();
+
+            _streamBuffers[currentPageCount++] = ArrayPool<byte>.Shared.Rent(PageSize);
+        }
+
+        _allocatedBytes = (long)currentPageCount * PageSize;
+        value = Math.Max(value, _length);
+        if (_position > (_length = value))
+        {
+            _position = _length;
+        }
+    }
+
+    public override bool CanRead => true;
+
+    public override bool CanSeek => true;
+
+    public override bool CanWrite => true;
+
+    public override long Length => _length;
+
+    public override long Position
+    {
+        get => _position;
+        set
+        {
+            if (value > _length)
+            {
+                throw new InvalidOperationException("Position > Length");
+            }
+
+            if (value < 0)
+            {
+                throw new InvalidOperationException("Position < 0");
+            }
+
+            _position = value;
+        }
+    }
+
+#if NETCOREAPP || NET452
+    public Span<byte[]> GetSpan()
+    {
+        return _streamBuffers.AsSpan(0, _streamBuffers.Length);
+    }
+
+    public Memory<byte[]> GetMemory()
+    {
+        return _streamBuffers.AsMemory(0, _streamBuffers.Length);
+    }
+    public ArraySegment<byte[]> ToArraySegment()
+    {
+        return new ArraySegment<byte[]>(_streamBuffers, 0, _streamBuffers.Length);
+    }
+#endif
+
+    public override void Flush()
+    {
+        AssertNotDisposed();
+    }
+
+    public override int Read(byte[] buffer, int offset, int count)
+    {
+        AssertNotDisposed();
+        int currentPage = (int)(_position / PageSize);
+        int currentOffset = (int)(_position % PageSize);
+        int currentLength = PageSize - currentOffset;
+        long startPosition = _position;
+
+        if (startPosition + count > _length)
+        {
+            count = (int)(_length - startPosition);
+        }
+
+        while (count != 0 && _position < _length)
+        {
+            if (currentLength > count)
+            {
+                currentLength = count;
+            }
+
+            Array.Copy(_streamBuffers[currentPage++], currentOffset, buffer, offset, currentLength);
+            offset += currentLength;
+            _position += currentLength;
+            count -= currentLength;
+            currentOffset = 0;
+            currentLength = PageSize;
+        }
+
+        return (int)(_position - startPosition);
+    }
+
+    public override long Seek(long offset, SeekOrigin origin)
+    {
+        AssertNotDisposed();
+        switch (origin)
+        {
+            case SeekOrigin.Begin:
+                break;
+
+            case SeekOrigin.Current:
+                offset += _position;
+                break;
+
+            case SeekOrigin.End:
+                offset = _length - offset;
+                break;
+
+            default:
+                throw new ArgumentOutOfRangeException("origin");
+        }
+
+        return Position = offset;
+    }
+
+    public override void SetLength(long value)
+    {
+        switch (value)
+        {
+            case < 0:
+                throw new InvalidOperationException("SetLength < 0");
+            case 0:
+                _streamBuffers = null;
+                _allocatedBytes = _position = _length = 0;
+                _pageCount = 0;
+                return;
+        }
+
+        int currentPageCount = GetPageCount(_allocatedBytes);
+        int neededPageCount = GetPageCount(value);
+
+        while (currentPageCount > neededPageCount)
+        {
+            ArrayPool<byte>.Shared.Return(_streamBuffers[--currentPageCount], true);
+            _streamBuffers[currentPageCount] = null;
+        }
+
+        AllocSpaceIfNeeded(value);
+        if (_position > (_length = value))
+        {
+            _position = _length;
+        }
+    }
+
+    public override void Write(byte[] buffer, int offset, int count)
+    {
+        AssertNotDisposed();
+        int currentPage = (int)(_position / PageSize);
+        int currentOffset = (int)(_position % PageSize);
+        int currentLength = PageSize - currentOffset;
+        AllocSpaceIfNeeded(_position + count);
+        while (count != 0)
+        {
+            if (currentLength > count)
+            {
+                currentLength = count;
+            }
+
+            Array.Copy(buffer, offset, _streamBuffers[currentPage++], currentOffset, currentLength);
+            offset += currentLength;
+            _position += currentLength;
+            count -= currentLength;
+            currentOffset = 0;
+            currentLength = PageSize;
+        }
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    protected override void Dispose(bool disposing)
+    {
+        if (disposing)
+        {
+            _isDisposed = true;
+            Position = 0;
+            _length = 0;
+
+            if (_streamBuffers != null)
+            {
+                foreach (var bytes in _streamBuffers)
+                {
+                    if (bytes != null)
+                    {
+                        ArrayPool<byte>.Shared.Return(bytes);
+                    }
+                }
+
+                _streamBuffers = null;
+            }
+        }
+
+        base.Dispose(disposing);
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    private void AssertNotDisposed()
+    {
+        if (_isDisposed)
+        {
+            throw new ObjectDisposedException(nameof(PooledMemoryStream));
+        }
+    }
+}

+ 233 - 0
Masuit.Tools.Abstractions/Systems/PooledMemoryStream.cs

@@ -0,0 +1,233 @@
+using System;
+using System.Buffers;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 池化内存流
+/// </summary>
+public sealed class PooledMemoryStream : Stream
+{
+    /// <summary>
+    /// 终结器
+    /// </summary>
+    ~PooledMemoryStream()
+    {
+        Dispose(true);
+    }
+
+    private const float OverExpansionFactor = 2;
+
+    private byte[] _data = Array.Empty<byte>();
+    private int _length;
+    private readonly ArrayPool<byte> _pool;
+    private bool _isDisposed;
+
+    public PooledMemoryStream() : this(ArrayPool<byte>.Shared)
+    {
+    }
+
+    public PooledMemoryStream(byte[] buffer) : this(ArrayPool<byte>.Shared, buffer.Length)
+    {
+        Array.Copy(buffer, 0, _data, 0, buffer.Length);
+    }
+
+    public PooledMemoryStream(ArrayPool<byte> arrayPool, int capacity = 0)
+    {
+        _pool = arrayPool ?? throw new ArgumentNullException(nameof(arrayPool));
+        if (capacity > 0)
+        {
+            _data = _pool.Rent(capacity);
+        }
+    }
+
+    public override bool CanRead => true;
+
+    public override bool CanSeek => true;
+
+    public override bool CanWrite => true;
+
+    public override long Length => _length;
+
+    public override long Position { get; set; }
+
+    public long Capacity => _data?.Length ?? 0;
+
+#if NETCOREAPP || NET452
+    public Span<byte> GetSpan()
+    {
+        return _data.AsSpan(0, _length);
+    }
+
+    public Memory<byte> GetMemory()
+    {
+        return _data.AsMemory(0, _length);
+    }
+    public ArraySegment<byte> ToArraySegment()
+    {
+        return new ArraySegment<byte>(_data, 0, (int)Length);
+    }
+#endif
+
+    public override void Flush()
+    {
+        AssertNotDisposed();
+    }
+
+    public override int Read(byte[] buffer, int offset, int count)
+    {
+        AssertNotDisposed();
+
+        if (count == 0)
+        {
+            return 0;
+        }
+
+        var available = Math.Min(count, Length - Position);
+        Array.Copy(_data, Position, buffer, offset, available);
+        Position += available;
+        return (int)available;
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public override long Seek(long offset, SeekOrigin origin)
+    {
+        AssertNotDisposed();
+
+        switch (origin)
+        {
+            case SeekOrigin.Current:
+                if (Position + offset < 0 || Position + offset > Capacity)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(offset));
+                }
+
+                Position += offset;
+                _length = (int)Math.Max(Position, _length);
+                return Position;
+
+            case SeekOrigin.Begin:
+                if (offset < 0 || offset > Capacity)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(offset));
+                }
+
+                Position = offset;
+                _length = (int)Math.Max(Position, _length);
+                return Position;
+
+            case SeekOrigin.End:
+                if (Length + offset < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(offset));
+                }
+
+                if (Length + offset > Capacity)
+                {
+                    SetCapacity((int)(Length + offset));
+                }
+
+                Position = Length + offset;
+                _length = (int)Math.Max(Position, _length);
+                return Position;
+
+            default:
+                throw new ArgumentOutOfRangeException(nameof(origin));
+        }
+    }
+
+    public override void SetLength(long value)
+    {
+        AssertNotDisposed();
+
+        if (value < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(value));
+        }
+
+        if (value > Capacity)
+        {
+            SetCapacity((int)value);
+        }
+
+        _length = (int)value;
+        if (Position > Length)
+        {
+            Position = Length;
+        }
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public override void Write(byte[] buffer, int offset, int count)
+    {
+        AssertNotDisposed();
+
+        if (count == 0)
+        {
+            return;
+        }
+
+        if (Capacity - Position < count)
+        {
+            SetCapacity((int)(OverExpansionFactor * (Position + count)));
+        }
+
+        Buffer.BlockCopy(buffer, offset, _data, (int)Position, count);
+        Position += count;
+        _length = (int)Math.Max(Position, _length);
+    }
+
+    public void WriteTo(Stream stream)
+    {
+        if (stream == null)
+        {
+            throw new ArgumentNullException(nameof(stream));
+        }
+
+        AssertNotDisposed();
+        stream.Write(_data, 0, (int)Length);
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    protected override void Dispose(bool disposing)
+    {
+        if (disposing)
+        {
+            _isDisposed = true;
+            Position = 0;
+            _length = 0;
+
+            if (_data != null)
+            {
+                _pool.Return(_data);
+                _data = null;
+            }
+        }
+
+        base.Dispose(disposing);
+    }
+
+    private void SetCapacity(int newCapacity)
+    {
+        var newData = _pool.Rent(newCapacity);
+
+        if (_data != null)
+        {
+            Buffer.BlockCopy(_data, 0, newData, 0, (int)Position);
+            _pool.Return(_data);
+        }
+
+        _data = newData;
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    private void AssertNotDisposed()
+    {
+        if (_isDisposed)
+        {
+            throw new ObjectDisposedException(nameof(PooledMemoryStream));
+        }
+    }
+}

+ 8 - 12
Masuit.Tools.AspNetCore/Extensions/MultipartRequestService.cs

@@ -1,14 +1,15 @@
-using System;
+using Masuit.Tools.Core.AspNetCore;
+using Masuit.Tools.Systems;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
-using Masuit.Tools.Core.AspNetCore;
-using Microsoft.AspNetCore.WebUtilities;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Primitives;
-using Microsoft.Net.Http.Headers;
 
 namespace Masuit.Tools.AspNetCore.Extensions;
 
@@ -34,10 +35,8 @@ public class MultipartRequestService : IMultipartRequestService
             }
             else if (contentDisposition.IsFileDisposition())
             {
-                // you will want to replace all of this because it copies the file into a memory stream. We don't want that.
-                await using var memoryStream = new MemoryStream();
+                await using var memoryStream = new PooledMemoryStream();
                 await section.Body.CopyToAsync(memoryStream, cancellationToken);
-
                 file = memoryStream.ToArray();
             }
         }
@@ -48,9 +47,6 @@ public class MultipartRequestService : IMultipartRequestService
     private Encoding GetEncoding(MultipartSection section)
     {
         var hasMediaTypeHeader = MediaTypeHeaderValue.TryParse(section.ContentType, out var mediaType);
-
-        // UTF-7 is insecure and shouldn't be honored. UTF-8 succeeds in
-        // most cases.
         if (!hasMediaTypeHeader || Encoding.UTF7.Equals(mediaType.Encoding))
         {
             return Encoding.UTF8;

+ 3 - 3
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -17,12 +17,12 @@
         <Product>Masuit.Tools.AspNetCore</Product>
         <PackageId>Masuit.Tools.AspNetCore</PackageId>
         <LangVersion>latest</LangVersion>
-        <Version>1.1.8.3</Version>
+        <Version>1.1.9-beta</Version>
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-        <FileVersion>$(Version)</FileVersion>
+        <FileVersion>1.1.9</FileVersion>
         <Company>masuit.com</Company>
-        <AssemblyVersion>$(Version)</AssemblyVersion>
+        <AssemblyVersion>1.1.9</AssemblyVersion>
         <Authors>懒得勤快</Authors>
         <RepositoryUrl>https://github.com/ldqk/Masuit.Tools</RepositoryUrl>
         <EmbedUntrackedSources>true</EmbedUntrackedSources>

+ 4 - 4
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -6,7 +6,7 @@
 官网教程:https://ldqk.org/55
 github:https://github.com/ldqk/Masuit.Tools
         </Description>
-        <Version>2.5.8.3</Version>
+        <Version>2.5.9-beta</Version>
         <Copyright>Copyright © 懒得勤快</Copyright>
         <PackageProjectUrl>https://github.com/ldqk/Masuit.Tools</PackageProjectUrl>
         <PackageTags>Masuit.Tools,工具库,Utility,Crypt,Extensions</PackageTags>
@@ -21,9 +21,9 @@ github:https://github.com/ldqk/Masuit.Tools
         <UserSecretsId>830c282f-f7c1-42be-8651-4cd06ac8e73f</UserSecretsId>
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-        <FileVersion>$(Version)</FileVersion>
+        <FileVersion>2.5.9</FileVersion>
         <Company>masuit.org</Company>
-        <AssemblyVersion>$(Version)</AssemblyVersion>
+        <AssemblyVersion>2.5.9</AssemblyVersion>
         <Authors>懒得勤快</Authors>
         <RepositoryUrl>https://github.com/ldqk/Masuit.Tools</RepositoryUrl>
         <EmbedUntrackedSources>true</EmbedUntrackedSources>
@@ -54,7 +54,7 @@ github:https://github.com/ldqk/Masuit.Tools
         <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10" />
     </ItemGroup>
     <ItemGroup Condition=" '$(TargetFramework)' == 'net7'">
-        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0" />
+        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.1" />
     </ItemGroup>
     <ItemGroup>
       <Compile Remove="..\Masuit.Tools.Abstractions\Mapping\**" />

+ 614 - 553
Masuit.Tools.Excel/ExcelExtension.cs

@@ -1,4 +1,5 @@
-using OfficeOpenXml;
+using Masuit.Tools.Systems;
+using OfficeOpenXml;
 using OfficeOpenXml.Style;
 using OfficeOpenXml.Table;
 using SixLabors.Fonts;
@@ -14,556 +15,616 @@ namespace Masuit.Tools.Excel;
 
 public static class ExcelExtension
 {
-	static ExcelExtension()
-	{
-		ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
-	}
-
-	/// <summary>
-	/// 将内存表自动填充到Excel
-	/// </summary>
-	/// <param name="sheetTables">sheet名和内存表的映射</param>
-	/// <param name="password">密码</param>
-	/// <param name="settings">列设置</param>
-	/// <returns>内存流</returns>
-	public static MemoryStream ToExcel(this Dictionary<string, DataTable> sheetTables, string password = null, ColumnSettings settings = null)
-	{
-		using var pkg = new ExcelPackage();
-		foreach (var pair in sheetTables)
-		{
-			pair.Value.TableName = pair.Key;
-			CreateWorksheet(pkg, pair.Value, settings);
-		}
-
-		return SaveAsStream(pkg, password);
-	}
-
-	/// <summary>
-	/// 将内存表自动填充到Excel
-	/// </summary>
-	/// <param name="sheetTables">sheet名和内存表的映射</param>
-	/// <param name="password">密码</param>
-	/// <param name="settings">列设置</param>
-	/// <returns>内存流</returns>
-	public static MemoryStream ToExcel<T>(this Dictionary<string, IEnumerable<T>> sheetTables, string password = null, ColumnSettings settings = null)
-	{
-		using var pkg = new ExcelPackage();
-		foreach (var pair in sheetTables)
-		{
-			CreateWorksheet(pkg, pair, settings);
-		}
-
-		return SaveAsStream(pkg, password);
-	}
-
-	/// <summary>
-	/// 将内存表自动填充到Excel
-	/// </summary>
-	/// <param name="tables">内存表</param>
-	/// <param name="password">密码</param>
-	/// <returns>内存流</returns>
-	public static MemoryStream ToExcel(this List<DataTable> tables, string password = null, ColumnSettings settings = null)
-	{
-		using var pkg = new ExcelPackage();
-		foreach (var table in tables)
-		{
-			CreateWorksheet(pkg, table, settings);
-		}
-
-		return SaveAsStream(pkg, password);
-	}
-
-	/// <summary>
-	/// 将内存表自动填充到Excel
-	/// </summary>
-	/// <param name="table">内存表</param>
-	/// <param name="password">密码</param>
-	/// <returns>内存流</returns>
-	public static MemoryStream ToExcel(this DataTable table, string password = null, ColumnSettings settings = null)
-	{
-		using var pkg = new ExcelPackage();
-		CreateWorksheet(pkg, table, settings);
-		return SaveAsStream(pkg, password);
-	}
-
-	/// <summary>
-	/// 将内存表自动填充到Excel
-	/// </summary>
-	/// <param name="table">内存表</param>
-	/// <param name="password">密码</param>
-	/// <returns>内存流</returns>
-	public static MemoryStream ToExcel<T>(this IEnumerable<T> table, string password = null, ColumnSettings settings = null)
-	{
-		using var pkg = new ExcelPackage();
-		CreateWorksheet(pkg, new KeyValuePair<string, IEnumerable<T>>("Sheet1", table), settings);
-		return SaveAsStream(pkg, password);
-	}
-
-	private static MemoryStream SaveAsStream(ExcelPackage pkg, string password)
-	{
-		var ms = new MemoryStream();
-		if (!string.IsNullOrEmpty(password))
-		{
-			pkg.SaveAs(ms, password);
-		}
-		else
-		{
-			pkg.SaveAs(ms);
-		}
-
-		return ms;
-	}
-
-	public static void CreateWorksheet(this ExcelPackage pkg, DataTable table, ColumnSettings settings = null)
-	{
-		if (string.IsNullOrEmpty(table.TableName))
-		{
-			table.TableName = "Sheet1";
-		}
-
-		var sheet = pkg.Workbook.Worksheets.Add(table.TableName);
-		sheet.Cells.Style.Font.Name = "微软雅黑";
-
-		FillWorksheet(sheet, table, settings);
-
-		sheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
-
-		//打印方向:纵向
-		sheet.PrinterSettings.Orientation = eOrientation.Landscape;
-
-		//集中在一页里打印
-		sheet.PrinterSettings.FitToPage = true;
-
-		//使用A4纸
-		sheet.PrinterSettings.PaperSize = ePaperSize.A4;
-	}
-
-	public static void CreateWorksheet<T>(this ExcelPackage pkg, KeyValuePair<string, IEnumerable<T>> table, ColumnSettings settings = null)
-	{
-		var sheet = pkg.Workbook.Worksheets.Add(table.Key);
-		sheet.Cells.Style.Font.Name = "微软雅黑";
-
-		FillWorksheet(sheet, table.Value, settings);
-
-		sheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
-
-		//打印方向:纵向
-		sheet.PrinterSettings.Orientation = eOrientation.Landscape;
-
-		//集中在一页里打印
-		sheet.PrinterSettings.FitToPage = true;
-
-		//使用A4纸
-		sheet.PrinterSettings.PaperSize = ePaperSize.A4;
-	}
-
-	/// <summary>
-	/// 从datatable填充工作簿
-	/// </summary>
-	/// <param name="sheet">工作簿</param>
-	/// <param name="table">数据</param>
-	/// <param name="settings">列设置</param>
-	/// <param name="startRow">起始行,默认第一行</param>
-	/// <param name="startColumn">起始列,默认第一列A列</param>
-	public static void FillWorksheet(this ExcelWorksheet sheet, DataTable table, ColumnSettings settings = null, int startRow = 1, int startColumn = 1)
-	{
-		var hasPicColumn = false;
-		if (table.Rows.Count > 0)
-		{
-			for (int i = 0; i < table.Columns.Count; i++)
-			{
-				switch (table.Rows[0][i])
-				{
-					case Stream:
-					case IEnumerable<Stream>:
-					case IDictionary<string, Stream>:
-					case IDictionary<string, MemoryStream>:
-						hasPicColumn = true;
-						break;
-				}
-			}
-
-			if (hasPicColumn)
-			{
-				// 填充表头
-				var maxWidth = new int[table.Columns.Count];
-				for (var j = 0; j < table.Columns.Count; j++)
-				{
-					sheet.SetValue(startRow, j + startColumn, table.Columns[j].ColumnName);
-					maxWidth[j] = Encoding.UTF8.GetBytes(table.Columns[j].ColumnName).Length;
-				}
-
-				sheet.Row(startRow).Style.Font.Bold = true; // 表头设置为粗体
-				sheet.Row(startRow).Style.Font.Size = sheet.Row(startRow).Style.Font.Size * 1.11f; // 表头字号放大1.11倍
-				sheet.Row(startRow).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
-				sheet.Row(startRow).CustomHeight = true; // 自动调整行高
-				if (settings != null)
-				{
-					foreach (var x in settings.ColumnTypes)
-					{
-						sheet.Column(x.Key).Style.Numberformat.Format = x.Value;
-					}
-				}
-				sheet.Cells.AutoFitColumns(); // 表头自适应列宽
-
-				// 填充内容
-				for (int i = 0; i < table.Rows.Count; i++)
-				{
-					sheet.Row(i + startRow + 1).CustomHeight = true; // 自动调整行高
-					for (int j = 0; j < table.Columns.Count; j++)
-					{
-						switch (table.Rows[i][j])
-						{
-							case Stream s:
-								{
-									if (s.Length > 2)
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), s);
-											picture.SetPosition(i + startRow, 3, j + startColumn - 1, 5); //设置图片显示位置
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											sheet.Row(i + startRow + 1).Height = 90;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{i + startRow}行{j}列图像格式不受支持");
-										}
-									}
-
-									sheet.SetValue(i + startRow + 1, j + startColumn, "");
-
-									break;
-								}
-
-							case IEnumerable<Stream> streams:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var stream in streams.Where(stream => stream.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), stream);
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(i + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持");
-										}
-									}
-
-									sheet.SetValue(i + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							case IDictionary<string, Stream> dic:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(i + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
-										}
-									}
-
-									sheet.SetValue(i + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							case IDictionary<string, MemoryStream> dic:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(i + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
-										}
-									}
-
-									sheet.SetValue(i + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							default:
-								{
-									sheet.SetValue(i + startRow + 1, j + startColumn, table.Rows[i][j] ?? "");
-									if (table.Rows[i][j] is ValueType)
-									{
-										sheet.Column(j + startColumn).AutoFit();
-									}
-									else
-									{
-										// 根据单元格内容长度来自适应调整列宽
-										var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == sheet.Cells[i + startRow + 1, j + startColumn].Style.Font.Name);
-										int measureSize = 1;
-										if (fontFamily == default)
-										{
-											fontFamily = SystemFonts.Families.FirstOrDefault();
-											measureSize++;
-										}
-
-										var width = TextMeasurer.Measure(table.Rows[i][j].ToString(), new TextOptions(fontFamily.CreateFont(measureSize))).Width;
-										sheet.Column(j + startColumn).Width = Math.Min(110, Math.Max(width, sheet.Column(j + startColumn).Width));
-									}
-
-									break;
-								}
-						}
-					}
-				}
-
-				sheet.Cells.Style.WrapText = true;
-			}
-			else
-			{
-				sheet.Cells[startRow, startColumn].LoadFromDataTable(table, true, TableStyles.Light15).AutoFitColumns(12, 90);
-				sheet.Cells.Style.WrapText = true;
-			}
-		}
-	}
-
-	/// <summary>
-	/// 从datatable填充工作簿
-	/// </summary>
-	/// <param name="sheet">工作簿</param>
-	/// <param name="table">数据</param>
-	/// <param name="settings">列设置</param>
-	/// <param name="startRow">起始行,默认第一行</param>
-	/// <param name="startColumn">起始列,默认第一列A列</param>
-	public static void FillWorksheet<T>(this ExcelWorksheet sheet, IEnumerable<T> source, ColumnSettings settings = null, int startRow = 1, int startColumn = 1)
-	{
-		var hasPicColumn = false;
-		var properties = typeof(T).GetProperties();
-		if (source is ICollection<T> table)
-		{
-		}
-		else
-		{
-			table = source.ToList();
-		}
-
-		if (table.Any())
-		{
-			if (properties.Any(t => t.PropertyType.IsSubclassOf(typeof(Stream)) || typeof(IEnumerable<Stream>).IsAssignableFrom(t.PropertyType) || (typeof(IDictionary).IsAssignableFrom(t.PropertyType) && t.PropertyType.GenericTypeArguments[1].IsSubclassOf(typeof(Stream)))))
-			{
-				hasPicColumn = true;
-			}
-
-			if (hasPicColumn)
-			{
-				// 填充表头
-				var maxWidth = new int[properties.Length];
-				for (var j = 0; j < properties.Length; j++)
-				{
-					sheet.SetValue(startRow, j + startColumn, properties[j].Name);
-					maxWidth[j] = Encoding.UTF8.GetBytes(properties[j].Name).Length;
-				}
-
-				sheet.Row(startRow).Style.Font.Bold = true; // 表头设置为粗体
-				sheet.Row(startRow).Style.Font.Size = sheet.Row(startRow).Style.Font.Size * 1.11f; // 表头字号放大1.11倍
-				sheet.Row(startRow).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
-				sheet.Row(startRow).CustomHeight = true; // 自动调整行高
-				if (settings != null)
-				{
-					foreach (var x in settings.ColumnTypes)
-					{
-						sheet.Column(x.Key).Style.Numberformat.Format = x.Value;
-					}
-				}
-				sheet.Cells.AutoFitColumns(); // 表头自适应列宽
-
-				// 填充内容
-				int current = 0;
-				foreach (var item in table)
-				{
-					sheet.Row(current + startRow + 1).CustomHeight = true; // 自动调整行高
-					for (int j = 0; j < properties.Length; j++)
-					{
-						switch (properties[j].GetValue(item))
-						{
-							case Stream s:
-								{
-									if (s.Length > 2)
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), s);
-											picture.SetPosition(current + startRow, 3, j + startColumn - 1, 5); //设置图片显示位置
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											sheet.Row(current + startRow + 1).Height = 90;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{current + startRow}行{j}列图像格式不受支持");
-										}
-									}
-
-									sheet.SetValue(current + startRow + 1, j + startColumn, "");
-
-									break;
-								}
-
-							case IEnumerable<Stream> streams:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var stream in streams.Where(stream => stream.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), stream);
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(current + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持");
-										}
-									}
-
-									sheet.SetValue(current + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							case IDictionary<string, Stream> dic:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(current + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
-										}
-									}
-
-									sheet.SetValue(current + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							case IDictionary<string, MemoryStream> dic:
-								{
-									double sumWidth = 0;
-									int index = 0;
-									foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
-									{
-										try
-										{
-											var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
-											var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
-											picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
-											sheet.Row(current + startRow + 1).Height = 90;
-											sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
-											sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
-											picture.SetSize((int)percent);
-										}
-										catch
-										{
-											throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持,图片链接: {kv.Key}");
-										}
-									}
-
-									sheet.SetValue(current + startRow + 1, j + startColumn, "");
-									break;
-								}
-
-							default:
-								{
-									sheet.SetValue(current + startRow + 1, j + startColumn, properties[j].GetValue(item) ?? "");
-									if (properties[j].GetValue(item) is ValueType)
-									{
-										sheet.Column(j + startColumn).AutoFit();
-									}
-									else
-									{
-										// 根据单元格内容长度来自适应调整列宽
-										var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == sheet.Cells[current + startRow + 1, j + startColumn].Style.Font.Name);
-										int measureSize = 1;
-										if (fontFamily == default)
-										{
-											fontFamily = SystemFonts.Families.FirstOrDefault();
-											measureSize++;
-										}
-
-										var width = TextMeasurer.Measure(properties[j].GetValue(item).ToString(), new TextOptions(fontFamily.CreateFont(measureSize))).Width;
-										sheet.Column(j + startColumn).Width = Math.Min(110, Math.Max(width, sheet.Column(j + startColumn).Width));
-									}
-
-									break;
-								}
-						}
-					}
-					current++;
-				}
-
-				sheet.Cells.Style.WrapText = true;
-			}
-			else
-			{
-				sheet.Cells[startRow, startColumn].LoadFromCollection(table, true, TableStyles.Light15).AutoFitColumns(12, 90);
-				sheet.Cells.Style.WrapText = true;
-			}
-		}
-	}
-
-	private static readonly NumberFormater NumberFormater = new("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1);
-
-	/// <summary>
-	/// 获取字母列
-	/// </summary>
-	/// <param name="sheet"></param>
-	/// <param name="index"></param>
-	/// <returns></returns>
-	public static ExcelColumn Column(this ExcelWorksheet sheet, string index)
-	{
-		return sheet.Column((int)NumberFormater.FromString(index));
-	}
+    static ExcelExtension()
+    {
+        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
+    }
+
+#if NET5_0_OR_GREATER
+    [System.Runtime.CompilerServices.ModuleInitializer]
+    internal static void Init()
+    {
+        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
+    }
+#endif
+
+    /// <summary>
+    /// 将内存表自动填充到Excel
+    /// </summary>
+    /// <param name="sheetTables">sheet名和内存表的映射</param>
+    /// <param name="password">密码</param>
+    /// <param name="settings">列设置</param>
+    /// <returns>内存流</returns>
+    public static PooledMemoryStream ToExcel(this Dictionary<string, DataTable> sheetTables, string password = null, ColumnSettings settings = null)
+    {
+        using var pkg = new ExcelPackage();
+        foreach (var pair in sheetTables)
+        {
+            pair.Value.TableName = pair.Key;
+            CreateWorksheet(pkg, pair.Value, settings);
+        }
+
+        return SaveAsStream(pkg, password);
+    }
+
+    /// <summary>
+    /// 将内存表自动填充到Excel
+    /// </summary>
+    /// <param name="sheetTables">sheet名和内存表的映射</param>
+    /// <param name="password">密码</param>
+    /// <param name="settings">列设置</param>
+    /// <returns>内存流</returns>
+    public static PooledMemoryStream ToExcel<T>(this Dictionary<string, IEnumerable<T>> sheetTables, string password = null, ColumnSettings settings = null)
+    {
+        using var pkg = new ExcelPackage();
+        foreach (var pair in sheetTables)
+        {
+            CreateWorksheet(pkg, pair, settings);
+        }
+
+        return SaveAsStream(pkg, password);
+    }
+
+    /// <summary>
+    /// 将内存表自动填充到Excel
+    /// </summary>
+    /// <param name="tables">内存表</param>
+    /// <param name="password">密码</param>
+    /// <returns>内存流</returns>
+    public static PooledMemoryStream ToExcel(this List<DataTable> tables, string password = null, ColumnSettings settings = null)
+    {
+        using var pkg = new ExcelPackage();
+        foreach (var table in tables)
+        {
+            CreateWorksheet(pkg, table, settings);
+        }
+
+        return SaveAsStream(pkg, password);
+    }
+
+    /// <summary>
+    /// 将内存表自动填充到Excel
+    /// </summary>
+    /// <param name="table">内存表</param>
+    /// <param name="password">密码</param>
+    /// <returns>内存流</returns>
+    public static PooledMemoryStream ToExcel(this DataTable table, string password = null, ColumnSettings settings = null)
+    {
+        using var pkg = new ExcelPackage();
+        CreateWorksheet(pkg, table, settings);
+        return SaveAsStream(pkg, password);
+    }
+
+    /// <summary>
+    /// 将内存表自动填充到Excel
+    /// </summary>
+    /// <param name="table">内存表</param>
+    /// <param name="password">密码</param>
+    /// <returns>内存流</returns>
+    public static PooledMemoryStream ToExcel<T>(this IEnumerable<T> table, string password = null, ColumnSettings settings = null)
+    {
+        using var pkg = new ExcelPackage();
+        CreateWorksheet(pkg, new KeyValuePair<string, IEnumerable<T>>("Sheet1", table), settings);
+        return SaveAsStream(pkg, password);
+    }
+
+    private static PooledMemoryStream SaveAsStream(ExcelPackage pkg, string password)
+    {
+        var ms = new PooledMemoryStream();
+        if (!string.IsNullOrEmpty(password))
+        {
+            pkg.SaveAs(ms, password);
+        }
+        else
+        {
+            pkg.SaveAs(ms);
+        }
+
+        return ms;
+    }
+
+    public static void CreateWorksheet(this ExcelPackage pkg, DataTable table, ColumnSettings settings = null)
+    {
+        if (string.IsNullOrEmpty(table.TableName))
+        {
+            table.TableName = "Sheet1";
+        }
+
+        var sheet = pkg.Workbook.Worksheets.Add(table.TableName);
+        sheet.Cells.Style.Font.Name = "微软雅黑";
+
+        FillWorksheet(sheet, table, settings);
+
+        sheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
+
+        //打印方向:纵向
+        sheet.PrinterSettings.Orientation = eOrientation.Landscape;
+
+        //集中在一页里打印
+        sheet.PrinterSettings.FitToPage = true;
+
+        //使用A4纸
+        sheet.PrinterSettings.PaperSize = ePaperSize.A4;
+    }
+
+    public static void CreateWorksheet<T>(this ExcelPackage pkg, KeyValuePair<string, IEnumerable<T>> table, ColumnSettings settings = null)
+    {
+        var sheet = pkg.Workbook.Worksheets.Add(table.Key);
+        sheet.Cells.Style.Font.Name = "微软雅黑";
+
+        FillWorksheet(sheet, table.Value, settings);
+
+        sheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Center;
+
+        //打印方向:纵向
+        sheet.PrinterSettings.Orientation = eOrientation.Landscape;
+
+        //集中在一页里打印
+        sheet.PrinterSettings.FitToPage = true;
+
+        //使用A4纸
+        sheet.PrinterSettings.PaperSize = ePaperSize.A4;
+    }
+
+    /// <summary>
+    /// 从datatable填充工作簿
+    /// </summary>
+    /// <param name="sheet">工作簿</param>
+    /// <param name="table">数据</param>
+    /// <param name="settings">列设置</param>
+    /// <param name="startRow">起始行,默认第一行</param>
+    /// <param name="startColumn">起始列,默认第一列A列</param>
+    public static void FillWorksheet(this ExcelWorksheet sheet, DataTable table, ColumnSettings settings = null, int startRow = 1, int startColumn = 1)
+    {
+        var hasPicColumn = false;
+        if (table.Rows.Count > 0)
+        {
+            for (int i = 0; i < table.Columns.Count; i++)
+            {
+                switch (table.Rows[0][i])
+                {
+                    case Stream:
+                    case IEnumerable<Stream>:
+                    case IDictionary<string, Stream>:
+                    case IDictionary<string, MemoryStream>:
+                        hasPicColumn = true;
+                        break;
+                }
+            }
+
+            if (hasPicColumn)
+            {
+                // 填充表头
+                var maxWidth = new int[table.Columns.Count];
+                for (var j = 0; j < table.Columns.Count; j++)
+                {
+                    sheet.SetValue(startRow, j + startColumn, table.Columns[j].ColumnName);
+                    maxWidth[j] = Encoding.UTF8.GetBytes(table.Columns[j].ColumnName).Length;
+                }
+
+                sheet.Row(startRow).Style.Font.Bold = true; // 表头设置为粗体
+                sheet.Row(startRow).Style.Font.Size = sheet.Row(startRow).Style.Font.Size * 1.11f; // 表头字号放大1.11倍
+                sheet.Row(startRow).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
+                sheet.Row(startRow).CustomHeight = true; // 自动调整行高
+                if (settings != null)
+                {
+                    foreach (var x in settings.ColumnTypes)
+                    {
+                        sheet.Column(x.Key).Style.Numberformat.Format = x.Value;
+                    }
+                }
+                sheet.Cells.AutoFitColumns(); // 表头自适应列宽
+
+                // 填充内容
+                for (int i = 0; i < table.Rows.Count; i++)
+                {
+                    sheet.Row(i + startRow + 1).CustomHeight = true; // 自动调整行高
+                    for (int j = 0; j < table.Columns.Count; j++)
+                    {
+                        switch (table.Rows[i][j])
+                        {
+                            case Stream s:
+                                {
+                                    if (s.Length > 2)
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), s);
+                                            picture.SetPosition(i + startRow, 3, j + startColumn - 1, 5); //设置图片显示位置
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            sheet.Row(i + startRow + 1).Height = 90;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{i + startRow}行{j}列图像格式不受支持");
+                                        }
+                                    }
+
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, "");
+
+                                    break;
+                                }
+
+                            case IEnumerable<Stream> streams:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var stream in streams.Where(stream => stream.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), stream);
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(i + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持");
+                                        }
+                                    }
+
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, Stream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(i + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, MemoryStream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(i + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, PooledMemoryStream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(i + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(i + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{i + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            default:
+                                {
+                                    sheet.SetValue(i + startRow + 1, j + startColumn, table.Rows[i][j] ?? "");
+                                    if (table.Rows[i][j] is ValueType)
+                                    {
+                                        sheet.Column(j + startColumn).AutoFit();
+                                    }
+                                    else
+                                    {
+                                        // 根据单元格内容长度来自适应调整列宽
+                                        var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == sheet.Cells[i + startRow + 1, j + startColumn].Style.Font.Name);
+                                        int measureSize = 1;
+                                        if (fontFamily == default)
+                                        {
+                                            fontFamily = SystemFonts.Families.FirstOrDefault();
+                                            measureSize++;
+                                        }
+
+                                        var width = TextMeasurer.Measure(table.Rows[i][j].ToString(), new TextOptions(fontFamily.CreateFont(measureSize))).Width;
+                                        sheet.Column(j + startColumn).Width = Math.Min(110, Math.Max(width, sheet.Column(j + startColumn).Width));
+                                    }
+
+                                    break;
+                                }
+                        }
+                    }
+                }
+
+                sheet.Cells.Style.WrapText = true;
+            }
+            else
+            {
+                sheet.Cells[startRow, startColumn].LoadFromDataTable(table, true, TableStyles.Light15).AutoFitColumns(12, 90);
+                sheet.Cells.Style.WrapText = true;
+            }
+        }
+    }
+
+    /// <summary>
+    /// 从datatable填充工作簿
+    /// </summary>
+    /// <param name="sheet">工作簿</param>
+    /// <param name="table">数据</param>
+    /// <param name="settings">列设置</param>
+    /// <param name="startRow">起始行,默认第一行</param>
+    /// <param name="startColumn">起始列,默认第一列A列</param>
+    public static void FillWorksheet<T>(this ExcelWorksheet sheet, IEnumerable<T> source, ColumnSettings settings = null, int startRow = 1, int startColumn = 1)
+    {
+        var hasPicColumn = false;
+        var properties = typeof(T).GetProperties();
+        if (source is ICollection<T> table)
+        {
+        }
+        else
+        {
+            table = source.ToList();
+        }
+
+        if (table.Any())
+        {
+            if (properties.Any(t => t.PropertyType.IsSubclassOf(typeof(Stream)) || typeof(IEnumerable<Stream>).IsAssignableFrom(t.PropertyType) || (typeof(IDictionary).IsAssignableFrom(t.PropertyType) && t.PropertyType.GenericTypeArguments[1].IsSubclassOf(typeof(Stream)))))
+            {
+                hasPicColumn = true;
+            }
+
+            if (hasPicColumn)
+            {
+                // 填充表头
+                var maxWidth = new int[properties.Length];
+                for (var j = 0; j < properties.Length; j++)
+                {
+                    sheet.SetValue(startRow, j + startColumn, properties[j].Name);
+                    maxWidth[j] = Encoding.UTF8.GetBytes(properties[j].Name).Length;
+                }
+
+                sheet.Row(startRow).Style.Font.Bold = true; // 表头设置为粗体
+                sheet.Row(startRow).Style.Font.Size = sheet.Row(startRow).Style.Font.Size * 1.11f; // 表头字号放大1.11倍
+                sheet.Row(startRow).Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
+                sheet.Row(startRow).CustomHeight = true; // 自动调整行高
+                if (settings != null)
+                {
+                    foreach (var x in settings.ColumnTypes)
+                    {
+                        sheet.Column(x.Key).Style.Numberformat.Format = x.Value;
+                    }
+                }
+                sheet.Cells.AutoFitColumns(); // 表头自适应列宽
+
+                // 填充内容
+                int current = 0;
+                foreach (var item in table)
+                {
+                    sheet.Row(current + startRow + 1).CustomHeight = true; // 自动调整行高
+                    for (int j = 0; j < properties.Length; j++)
+                    {
+                        switch (properties[j].GetValue(item))
+                        {
+                            case Stream s:
+                                {
+                                    if (s.Length > 2)
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), s);
+                                            picture.SetPosition(current + startRow, 3, j + startColumn - 1, 5); //设置图片显示位置
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            sheet.Row(current + startRow + 1).Height = 90;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{current + startRow}行{j}列图像格式不受支持");
+                                        }
+                                    }
+
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, "");
+
+                                    break;
+                                }
+
+                            case IEnumerable<Stream> streams:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var stream in streams.Where(stream => stream.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), stream);
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(current + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持");
+                                        }
+                                    }
+
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, Stream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(current + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持,图片链接:{kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, MemoryStream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(current + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持,图片链接: {kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            case IDictionary<string, PooledMemoryStream> dic:
+                                {
+                                    double sumWidth = 0;
+                                    int index = 0;
+                                    foreach (var kv in dic.Where(kv => kv.Value.Length > 2))
+                                    {
+                                        try
+                                        {
+                                            var picture = sheet.Drawings.AddPicture(Guid.NewGuid().ToString(), kv.Value, new Uri(kv.Key));
+                                            var percent = Math.Round(Math.Min(120f / picture.Image.Bounds.Height * picture.Image.Bounds.VerticalResolution, 100));
+                                            picture.SetPosition(current + startRow, 3, j + startColumn - 1, (int)Math.Ceiling(picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent * index++)); //设置图片显示位置
+                                            sheet.Row(current + startRow + 1).Height = 90;
+                                            sumWidth += picture.Image.Bounds.Width / picture.Image.Bounds.HorizontalResolution * percent / 6.4;
+                                            sheet.Column(j + startColumn).Width = Math.Max(sheet.Column(j + startColumn).Width, sumWidth);
+                                            picture.SetSize((int)percent);
+                                        }
+                                        catch
+                                        {
+                                            throw new ArgumentException($"{current + startRow}行{j}列第{index}张图像格式不受支持,图片链接: {kv.Key}");
+                                        }
+                                    }
+
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, "");
+                                    break;
+                                }
+
+                            default:
+                                {
+                                    sheet.SetValue(current + startRow + 1, j + startColumn, properties[j].GetValue(item) ?? "");
+                                    if (properties[j].GetValue(item) is ValueType)
+                                    {
+                                        sheet.Column(j + startColumn).AutoFit();
+                                    }
+                                    else
+                                    {
+                                        // 根据单元格内容长度来自适应调整列宽
+                                        var fontFamily = SystemFonts.Families.FirstOrDefault(f => f.Name == sheet.Cells[current + startRow + 1, j + startColumn].Style.Font.Name);
+                                        int measureSize = 1;
+                                        if (fontFamily == default)
+                                        {
+                                            fontFamily = SystemFonts.Families.FirstOrDefault();
+                                            measureSize++;
+                                        }
+
+                                        var width = TextMeasurer.Measure(properties[j].GetValue(item).ToString(), new TextOptions(fontFamily.CreateFont(measureSize))).Width;
+                                        sheet.Column(j + startColumn).Width = Math.Min(110, Math.Max(width, sheet.Column(j + startColumn).Width));
+                                    }
+
+                                    break;
+                                }
+                        }
+                    }
+                    current++;
+                }
+
+                sheet.Cells.Style.WrapText = true;
+            }
+            else
+            {
+                sheet.Cells[startRow, startColumn].LoadFromCollection(table, true, TableStyles.Light15).AutoFitColumns(12, 90);
+                sheet.Cells.Style.WrapText = true;
+            }
+        }
+    }
+
+    private static readonly NumberFormater NumberFormater = new("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1);
+
+    /// <summary>
+    /// 获取字母列
+    /// </summary>
+    /// <param name="sheet"></param>
+    /// <param name="index"></param>
+    /// <returns></returns>
+    public static ExcelColumn Column(this ExcelWorksheet sheet, string index)
+    {
+        return sheet.Column((int)NumberFormater.FromString(index));
+    }
 }

+ 2 - 2
Masuit.Tools.Excel/Masuit.Tools.Excel.csproj

@@ -3,7 +3,7 @@
         <TargetFramework>netstandard2.0</TargetFramework>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>1.2.4.3</Version>
+        <Version>1.2.5-beta</Version>
         <Authors>懒得勤快</Authors>
         <Description>Masuit.Tools.Excel导出库,支持一些简单数据的导出,支持图片列</Description>
         <Copyright>懒得勤快</Copyright>
@@ -16,7 +16,7 @@
         <RepositoryType>Github</RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
         <PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
-        <FileVersion>1.2.3.2</FileVersion>
+        <FileVersion>1.2.4</FileVersion>
         <Company>masuit.org</Company>
         <AssemblyVersion>1.2.3</AssemblyVersion>
         <PackageLicenseUrl>https://github.com/ldqk/Masuit.Tools/blob/master/LICENSE</PackageLicenseUrl>

+ 1 - 1
Test/Masuit.Tools.Core.Test/Masuit.Tools.Core.Test.csproj

@@ -9,7 +9,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.0" />
+    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="7.0.1" />
     <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
     <PackageReference Include="xunit" Version="2.4.2" />