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

ESP32写入GPX文件时如何正确替换末尾闭合标签?

问题:ESP32写入GPX文件时无法正确替换末尾闭合标签

我正在ESP32上开发GPS轨迹写入SD卡GPX文件的功能,每次添加新轨迹点时需要先移除文件末尾的闭合标签</trkseg></trk></gpx>,再写入新点,最后重新加上闭合标签。但现有代码中计算文件偏移量的部分存在错误,导致无法正确操作。

现有完整代码:

if (gpsFixExists && dateIsValid && timeIsValid)
{
  if (state.currentGPXFile == "")
  {
    String filename = "/" + String(state.dateYear) + String(state.dateMonth) + String(state.dateDay) + "_" + String(state.timeHours) + String(state.timeMinutes) + String(state.timeSeconds) + ".gpx";
    state.currentGPXFile = filename.c_str();
    File gpxFile = SD.open(state.currentGPXFile.c_str(), FILE_WRITE);
    // Write GPX header and metadata
    gpxFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");
    gpxFile.println("<gpx version=\"1.1\" creator=\"Open Rally Computer - https://github.com/pcace/open-rally-computer\">");
    gpxFile.println("<metadata>");
    gpxFile.println("<name>" + filename + "</name>");
    gpxFile.println("<desc>Track log generated by Open Rally Computer</desc>");
    gpxFile.println("</metadata>");
    gpxFile.println("<trk><name>Track Log</name><trkseg>");
    gpxFile.close();
  }

  // Open the file to append data
  File gpxFile = SD.open(state.currentGPXFile.c_str(), FILE_WRITE);
  if (gpxFile)
  {
    // Move to the end of the file, then seek back to overwrite the closing tags
    long position = gpxFile.size() - strlen("</trkseg></trk></gpx>") - 1; // Adjusted to account for newline characters
    gpxFile.seek(position);
    // Write the new track point
    gpxFile.println("<trkpt lat=\"" + String(state.currentLatitude, 6) + "\" lon=\"" + String(state.currentLongitude, 6) + "\">");
    gpxFile.println("<ele>" + String(state.currentAltitude, 2) + "</ele>");
    gpxFile.println("<time>" + String(state.dateYear) + "-" + String(state.dateMonth) + "-" + String(state.dateDay) + "T" + String(state.timeHours) + ":" + String(state.timeMinutes) + ":" + String(state.timeSeconds) + "Z</time>");
    gpxFile.println("</trkpt>");
    // Re-append the closing tags
    gpxFile.println("</trkseg></trk></gpx>");
    gpxFile.close();
  }
}

其中以下两行逻辑错误:

long position = gpxFile.size() - strlen("</trkseg></trk></gpx>") - 1; // Adjusted to account for newline characters
gpxFile.seek(position);

问题根源

  • println()方法会在每行末尾写入**\r\n换行符**(共2个字节),原代码仅减去1个字节,完全不匹配实际换行长度。
  • 首次创建文件时未写入闭合标签,导致第一次追加时计算的偏移位置为负数,seek()操作无效。

修正方案

1. 初始化文件时补全闭合标签

首次创建文件时就写入完整的闭合标签,让后续追加逻辑有统一的末尾可处理:

if (state.currentGPXFile == "")
{
  String filename = "/" + String(state.dateYear) + String(state.dateMonth) + String(state.dateDay) + "_" + String(state.timeHours) + String(state.timeMinutes) + String(state.timeSeconds) + ".gpx";
  state.currentGPXFile = filename.c_str();
  File gpxFile = SD.open(state.currentGPXFile.c_str(), FILE_WRITE);
  // Write GPX header and metadata
  gpxFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");
  gpxFile.println("<gpx version=\"1.1\" creator=\"Open Rally Computer - https://github.com/pcace/open-rally-computer\">");
  gpxFile.println("<metadata>");
  gpxFile.println("<name>" + filename + "</name>");
  gpxFile.println("<desc>Track log generated by Open Rally Computer</desc>");
  gpxFile.println("</metadata>");
  gpxFile.println("<trk><name>Track Log</name><trkseg>");
  // 初始化时写入闭合标签,统一后续追加逻辑
  gpxFile.println("</trkseg></trk></gpx>");
  gpxFile.close();
}

2. 正确计算偏移位置

println("</trkseg></trk></gpx>")实际写入的内容是标签字符串加上\r\n,总长度为标签长度+2。修改偏移计算逻辑:

// Open the file to append data
File gpxFile = SD.open(state.currentGPXFile.c_str(), FILE_WRITE);
if (gpxFile)
{
  const char* closingTags = "</trkseg></trk></gpx>";
  // 计算闭合标签+换行符的总长度
  long closingLength = strlen(closingTags) + 2;
  // 移动到闭合标签的起始位置
  long position = gpxFile.size() - closingLength;
  
  // 防止位置非法(比如初始化异常)
  if (position >= 0) {
    gpxFile.seek(position);
  }
  
  // 写入新轨迹点
  gpxFile.println("<trkpt lat=\"" + String(state.currentLatitude, 6) + "\" lon=\"" + String(state.currentLongitude, 6) + "\">");
  gpxFile.println("<ele>" + String(state.currentAltitude, 2) + "</ele>");
  gpxFile.println("<time>" + String(state.dateYear) + "-" + String(state.dateMonth) + "-" + String(state.dateDay) + "T" + String(state.timeHours) + ":" + String(state.timeMinutes) + ":" + String(state.timeSeconds) + "Z</time>");
  gpxFile.println("</trkpt>");
  // 重新写入闭合标签
  gpxFile.println(closingTags);
  gpxFile.close();
}

3. 额外优化建议

  • 减少文件打开/关闭次数:可以保持文件持续打开(只要设备不意外断电),降低SD卡IO损耗,提升性能。
  • 增加错误检查:判断seek()的返回值是否成功,避免写入位置错误。
  • 避免频繁使用String拼接:可以用snprintf()预格式化字符串,减少内存碎片。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:20:55