You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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文件,或者我的实现方式是否有误?


问题分析与解决方案

核心错误点

  1. 二进制写入错误:ESP32端使用file.print()写入数据,该方法是按ASCII字符编码写入,而JPG是二进制文件,大量字节属于非可打印ASCII字符,会被转换或丢失,直接导致文件损坏。
  2. 文件重复打开问题:在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");
  }
}

额外优化建议

  1. 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);
}
  1. 添加数据校验机制:C#端先发送图片的字节总长度,ESP32端先接收长度值,再精准读取对应字节数,避免数据丢失或多余写入,进一步保证文件完整性。

内容的提问来源于stack exchange,提问作者baelzabubba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 08:55:28