ESP32如何将SD卡读取的URL转为const char*[]并让指针指向它
我需要从ESP32的SD卡中读取电台URL列表,这些URL以带引号的字符串形式存储,每行一个,格式为"http://xxx",(逗号结尾+换行)。目前已通过SD.h将URL存入String url[100];数组,但所用ESP32音频套件要求URL必须通过预定义的const char *urls[]指针数组传入,而非动态读取的String数组。
我尝试用char u[100][255]存储转换后的URL,编写了如下转换代码,但串口打印URL正常,音频却无法播放(直接在代码里初始化const char *urls[]时音频能正常工作):
int readurls(String url[],char u[100][255]){ File url_list = SD.open("/URLs/URL_LIST.txt"); String str; String a_url; int count = 0; while (url_list.available() && count < MAX_LINES) { str= url_list.readStringUntil('\n'); //Serial.println(str); int delim = str.indexOf(','); //a_url=str.substring(0,delim); //needed to eliminate the quotes from the strings a_url=str.substring(3,delim-1); url[count] = a_url; // works to this point - that is String Array looks correct a_url+="\0"; // tried to add a null pointer several ways //Serial.println(url[count].c_str()); char ubuf[a_url.length()+1]=""; a_url.toCharArray(ubuf,a_url.length()+1); strncpy(u[count],ubuf,sizeof(u[count])); //u[count]=url[count].c_str(); urls[count]=u[count]; count++; } close(url_list); return(count); }
1. const char *urls[]的常量属性冲突
你定义的urls是const char *类型数组,意味着指针指向的内容不可修改,但代码中直接给urls[count]赋值u[count]会触发未定义行为。解决方案:将urls改为非const的指针数组:
char *urls[100]; // 去掉const,适配动态赋值需求
如果音频套件强制要求const char *,可将u数组定义为全局静态常量,或使用const_cast(仅临时应急,不推荐长期使用)。
2. strncpy未添加空终止符
strncpy不会自动在目标数组末尾添加'\0',若URL长度刚好等于255,u[count]将没有字符串终止符,导致音频套件读取到乱码。解决方案:手动添加终止符:
strncpy(u[count], ubuf, sizeof(u[count]) - 1); // 预留一个位置放终止符 u[count][sizeof(u[count]) - 1] = '\0'; // 强制添加空终止符
3. 文件关闭方式错误
代码中close(url_list)调用错误,SD库的File对象需调用自身成员函数关闭:
url_list.close(); // 替换close(url_list)
4. 字符串解析的鲁棒性问题
原代码用固定下标substring(3, delim-1)截取URL,依赖严格的格式,若SD卡中存在格式异常的行(如空格、引号位置偏移),会导致URL截取错误。解决方案:改用引号位置定位截取,提升兼容性:
int startQuote = str.indexOf('"'); int endQuote = str.indexOf('"', startQuote + 1); if (startQuote != -1 && endQuote != -1) { a_url = str.substring(startQuote + 1, endQuote); } else { continue; // 格式错误,跳过当前行 }
5. 局部数组ubuf的冗余与风险
ubuf是栈上局部数组,存在栈溢出风险,直接用u[count]作为toCharArray的目标更高效安全:
a_url.toCharArray(u[count], sizeof(u[count])); // 替代原代码中ubuf的中间转换步骤
修复后的完整代码示例
#define MAX_LINES 100 char u[100][255]; char *urls[100]; // 改为非const指针数组 int readurls(String url[]){ File url_list = SD.open("/URLs/URL_LIST.txt"); if (!url_list) { // 添加文件打开失败判断 Serial.println("Failed to open URL_LIST.txt"); return 0; } String str; String a_url; int count = 0; while (url_list.available() && count < MAX_LINES) { str = url_list.readStringUntil('\n'); str.trim(); // 去除行首行尾的空格和换行符 if (str.isEmpty()) { // 跳过空行 continue; } // 用引号位置截取URL,更可靠 int startQuote = str.indexOf('"'); int endQuote = str.indexOf('"', startQuote + 1); if (startQuote == -1 || endQuote == -1) { Serial.println("Invalid line format: " + str); continue; } a_url = str.substring(startQuote + 1, endQuote); url[count] = a_url; // 直接将String转换到u数组 size_t urlLen = a_url.length(); if (urlLen >= sizeof(u[count])) { Serial.println("URL too long: " + a_url); continue; } a_url.toCharArray(u[count], sizeof(u[count])); urls[count] = u[count]; count++; } url_list.close(); return count; }
内容的提问来源于stack exchange,提问作者waszee

