用 File.ReadAllBytes
最快读取图片为 byte[]
如果只是把磁盘上已存在的图片文件(如
"logo.png")转成字节数组,
File.ReadAllBytes是最直接、安全且性能最好的方式。它自动处理文件打开、读取、关闭全过程,无需手动管理流。 适用于 JPG、PNG、BMP 等所有二进制图片格式,不关心编码或像素数据 注意:该方法会将整个文件一次性加载到内存,大图(如 >100MB)可能触发
OutOfMemoryException路径错误时抛出
FileNotFoundException,建议加
File.Exists判断或 try-catch
示例:
string imagePath = @"C:\assets\icon.jpg";
if (File.Exists(imagePath))
{
byte[] imageData = File.ReadAllBytes(imagePath);
// 后续可存入数据库、上传、加密等
}
用 Image.Save
+ MemoryStream
从 System.Drawing.Image
对象导出字节流
当你已经用
Image.FromFile、
Image.FromStream或 GDI+ 绘图后得到一个
Image实例,又需要把它“保存为某种格式的字节”,就得走
MemoryStream这条路。这里的关键是:必须显式指定图像格式(如
ImageFormat.Png),否则默认行为不可靠。 不指定格式时,
image.RawFormat可能是未知或不支持的编码,导致保存失败或乱码 使用
using确保
MemoryStream和
Image正确释放,尤其在服务端高频调用时避免 GDI 句柄泄漏 若原图是 JPEG,但用
ImageFormat.Png保存,会真正执行一次编码转换——不是简单复制字节
示例:
using (var image = Image.FromFile(@"C:\temp\photo.jpg"))
using (var ms = new MemoryStream())
{
image.Save(ms, ImageFormat.Jpeg); // 必须明确指定格式
byte[] jpegBytes = ms.ToArray();
}
用 Bitmap.LockBits
获取原始像素字节(仅限位图操作场景)
当你要做图像处理(如灰度化、卷积滤波、OCR 预处理),需要直接访问每个像素的 RGB 值,就不能用上面两种“文件级”转换方式。
LockBits提供的是未经压缩的、按扫描线排列的原始像素内存指针,返回的是真正的图像数据本体,而非文件容器(BMP 头、JPG Huffman 表等)。 只适用于
Bitmap类型;
Image抽象类不支持
LockBits返回的
byte[]不含任何文件头,长度 = 宽 × 高 × 每像素字节数(如 24 位 RGB 就是 ×3) 必须配对调用
UnlockBits,否则资源泄露;且不能跨线程访问同一块锁定内存 常见误用:把
LockBits得到的字节数组直接当 JPEG 文件写入磁盘——结果打不开
注意 byte[]
→ 图片反向转换时的格式陷阱
把字节数组还原成可用图片时,最常踩的坑是忽略来源格式。比如你用
File.ReadAllBytes("a.jpg") 得到的 byte[],必须用
Image.FromStream(new MemoryStream(data))加载,而不能直接传给
Bitmap构造函数(后者只接受原始像素布局,不识别 JPEG 头)。
Image.FromStream能自动识别 PNG/JPEG/GIF/BMP 等格式头,是最通用的选择 如果字节数组来自网络响应(如
HttpClient.GetByteArrayAsync),确保响应内容类型正确,且未被 gzip 压缩(否则需先解压) 从数据库读出的
byte[]若无法显示,优先检查是否在存入前被意外 Base64 编码过,或传输中截断
真正容易被忽略的是:不同 .NET 版本对图像编解码器的支持有差异。.NET 6+ 默认禁用某些旧格式(如 TIFF),需手动注册 —— 如果你发现某张 TIFF 图片在新项目里加载失败,不是代码问题,而是缺了
System.Drawing.Common的额外配置。
