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
相关产品推荐
相关产品推荐

