从C# Windows Form应用向ESP32 TCP服务器发送JPG图片的问题
问题:C#发送JPG图片到ESP32后无法保存为有效JPG文件
我正在开发一个项目,需将JPG图片从C#应用发送到ESP32,希望将图片存储在ESP32的SD卡中,再在ILI9341 TFT模块上显示。
C#端代码
图片转字节数组及发送触发代码
private void button1_Click(object sender, EventArgs e) { System.Drawing.Image newImage = Image.FromFile("gargoyle_1.jpg"); byte[] data = ImageClientModel.imageToByteArray(newImage); tcpFunctions.connect(config.EndPoint, config.Port, data); } internal static class ImageClientModel { public static byte[] imageToByteArray(this System.Drawing.Image image) { using (var ms = new MemoryStream()) { image.Save(ms, image.RawFormat); return ms.ToArray(); } } }
TCP发送类代码
public class tcpFunctions { public static String connect(string ep, Int32 port, byte[] data) { try { TcpClient client = new TcpClient(ep, port); NetworkStream stream = client.GetStream(); stream.Write(data); stream.Flush(); stream.Close(); client.Close(); return "OK"; } catch (IOException e) { String responseData = String.Empty; responseData = e.Message; return responseData; } catch (SocketException e) { String responseData = String.Empty; responseData = e.Message; return responseData; } finally { //nothing } } }
ESP32端接收代码
void loop() { WiFiClient client = wifiServer.available(); uint size=0; byte nString; File file; if (client) { while (client.connected()) { file = SD.open(imageFile, FILE_WRITE); while ((size = client.available())>0) { file.print(client.read()); } delay(10); } file.close(); Serial.println("File Closed"); client.stop(); } }
目前保存的“newImage.jpg”仅为字节数组数据,并非可用的JPG格式文件。我想知道如何将接收到的字节数组还原为可用JPG文件,或者我的实现方式是否有误?
问题分析与解决方案
核心错误点
- 二进制写入错误:ESP32端使用
file.print()写入数据,该方法是按ASCII字符编码写入,而JPG是二进制文件,大量字节属于非可打印ASCII字符,会被转换或丢失,直接导致文件损坏。 - 文件重复打开问题:在
while(client.connected())循环内反复打开文件,每次打开会重置文件指针或覆盖已有内容,导致写入逻辑混乱。
修正后的ESP32端代码
void loop() { WiFiClient client = wifiServer.available(); uint size = 0; byte buffer[1024]; // 用缓冲区批量读取,提升传输效率 File file; if (client) { Serial.println("Client connected"); // 仅在客户端连接时打开一次文件,FILE_WRITE模式:不存在则创建,存在则追加 file = SD.open(imageFile, FILE_WRITE); if (!file) { Serial.println("Failed to open file for writing"); client.stop(); return; } // 循环读取数据直到客户端断开连接 while (client.connected()) { size = client.available(); if (size > 0) { // 读取数据到缓冲区,单次最多读取缓冲区大小的内容 int readBytes = client.read(buffer, min(size, sizeof(buffer))); // 使用file.write()写入原始二进制数据 file.write(buffer, readBytes); } delay(10); } file.close(); Serial.println("File Closed"); client.stop(); Serial.println("Client disconnected"); } }
额外优化建议
- C#端简化文件读取逻辑:如果只是原封不动发送JPG文件,无需先转换为
Image对象,直接读取文件字节更高效,还能避免格式转换潜在的问题:
private void button1_Click(object sender, EventArgs e) { byte[] data = File.ReadAllBytes("gargoyle_1.jpg"); tcpFunctions.connect(config.EndPoint, config.Port, data); }
- 添加数据校验机制:C#端先发送图片的字节总长度,ESP32端先接收长度值,再精准读取对应字节数,避免数据丢失或多余写入,进一步保证文件完整性。
内容的提问来源于stack exchange,提问作者baelzabubba
相关产品推荐
相关产品推荐

