我想要一些关于如何摆脱重复变量的指导。
char Temp_File[40] ="/";
char End_File[8] = ".csv";
File Parameter_File;
我不确定在哪里声明这些变量,以便它们可以被库中的所有函数使用,但不会干扰主程序使用库时(此处不包括)。
这是一个关于 esp32-C3 芯片的项目,我正在使用 Arduino IDE 对所述芯片进行编程
这是我的库的 .h 和 .cpp 文件
Info_Saver.h 文件
#ifndef INFO_SAVER_H
#define INFO_SAVER_H
#include "FS.h"
#include "FFat.h"
namespace Info_Saver{
class Info_Saver {
#define FORMAT_FFAT true
public:
void Save_Info(char * File_Name, int Value_In);
void Format_Space();
void Delete_Parameter(char * File_Name);
void Read_Parameter(char * File_Name, char * Value_Out);
void List_Dir(const char * Dir_Name, uint8_t levels);
};
}
#endif
Info_Saver.cpp 文件
#include "Info_Saver.h"
void Info_Saver::Info_Saver::Save_Info(char * File_Name, int Value_In) {
char Temp_File[40] ="/";
char End_File[8] = ".csv";
File Parameter_File;
strcat(Temp_File, File_Name);
strcat(Temp_File, End_File);
//Serial.println(File_Name);
//Serial.println(Temp_File);
Parameter_File = FFat.open(Temp_File,FILE_WRITE);
if(!Parameter_File){
Serial.println("- failed to open file for writing");
} else {
Parameter_File.print(Value_In);
Parameter_File.print('\n');
//Serial.print("The value is: ");
//Serial.println(Value_In);
}
Parameter_File.close();
strcpy(Temp_File, "/");
return;
}
void Info_Saver::Info_Saver::Format_Space() {
if (!FFat.begin()) {
FFat.format();
}
return;
}
void Info_Saver::Info_Saver::Delete_Parameter(char * File_Name) {
char Temp_File[40] ="/";
char End_File[8] = ".csv";
File Parameter_File;
strcat(Temp_File, File_Name);
strcat(Temp_File,End_File);
//Serial.println(File_Name);
//Serial.println(Temp_File);
if(FFat.remove(Temp_File)) {
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
strcpy(Temp_File, "/");
return;
}
void Info_Saver::Info_Saver::Read_Parameter(char * File_Name, char * Value_Out) {
char Temp_File[40] ="/";
char End_File[8] = ".csv";
File Parameter_File;
char Temp_Out;
strcat(Temp_File, File_Name);
strcat(Temp_File,End_File);
//Serial.println(File_Name);
//Serial.println(Temp_File);
Parameter_File = FFat.open(Temp_File);
if(!Parameter_File || Parameter_File.isDirectory()) {
// add || Parameter_File.isDirectory() if there are issues
Serial.print("- failed to open file for reading");
Serial.print("\n");
} else {
while(Parameter_File.available()) {
static unsigned int Temp_Int = 0;
Temp_Out = Parameter_File.read();
if (Temp_Out != '\n' && Temp_Int < 7) {
Value_Out[Temp_Int] = Temp_Out;
Temp_Int++;
} else {
Value_Out[Temp_Int] = '\0';
Temp_Int = 0;
break;
}
}
//Serial.print("The value is: ");
//Serial.print(Value_Out);
//Serial.print("\n");
}
Parameter_File.close();
strcpy(Temp_File, "/");
return;
}
void Info_Saver::Info_Saver::List_Dir(const char * Dir_Name, uint8_t levels) {
File Root;
Root = FFat.open(Dir_Name);
if (!Root) {
Serial.println("- failed to open directory");
return;
} else if (!Root.isDirectory()) {
Serial.println(" - not a directory");
return;
}
File Temp_Root = Root.openNextFile();
while(Temp_Root){
if(Temp_Root.isDirectory()){
Serial.print(" DIR : ");
Serial.println(Temp_Root.name());
if(levels){
List_Dir(Temp_Root.path(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(Temp_Root.name());
Serial.print("\tSIZE: ");
Serial.println(Temp_Root.size());
}
Temp_Root = Root.openNextFile();
}
return;
}
我试过在 .h 文件和 .cpp 文件的开头声明变量。当在 .h 文件中声明变量时,我无法让程序运行。这很容易成为我如何在 .h 文件中声明它们的问题,我只是不确定如何正确地做到这一点。
当我在.cpp文件的开头声明变量时,我意识到变量变成了全局变量。这反过来又对主程序造成了严重破坏。不过,它确实允许我在所有函数中使用变量。
我认为您在
.h
或 .cpp
中声明这些变量时遇到的问题是,在这两种情况下,它都使变量成为全局变量(除非您将它们声明为成员变量)。像那样使变量成为全局变量确实会造成破坏。
我会尝试通过重新考虑您的类接口来解决这个问题。我认为
Info_Saver
不应该担心 CSV 文件路径或扩展名,因为这会产生问题:
char * File_Name
参数中并不明显。.csv
附加到File_Name
对于此类的用户来说是完全不可见的,因为它是一个实现细节。 Info_Saver
不应该有这个责任(SOLID原则的第一)。/
+ .csv
+ /
和空字节需要 7 个字符)。你的char Temp_File[40]
只有这么多空间因此,您可以改为考虑以下接口:
class Info_Saver {
#define FORMAT_FFAT true
public:
void Save_Info(const char * Csv_File_Path, int Value_In);
void Format_Space();
void Delete_Parameter(const char * Csv_File_Path);
void Read_Parameter(const char * Csv_File_Path, char * Value_Out);
void List_Dir(const char * Dir_Name, uint8_t levels);
};
通过这些接口更改,现在可以从实现中删除重复的参数修改:
char Temp_File[40] ="/";
char End_File[8] = ".csv";
strcat(Temp_File, File_Name);
strcat(Temp_File, End_File);
这带来了几个好处:
.csv
现在是用户的实现细节。如果这很常见,您可以将它实现为一个单独的函数,以便此类的用户可以使用它。Info_Saver
再也不用担心提供的文件路径有多大了此外,您还可以考虑其他一些设计决策:
List_Dir
是否属于Info_Saver
。这看起来更像是一个通用的文件夹列表实用程序,而不是与Info_Saver
.Info_Saver
对象仅在单个 CSV 文件上工作,从而减少重复参数。否则,几乎不需要类,因为您可以将这些方法实现为自由函数。例如,在这个设计中,每个方法都作用于
m_Csv_File_Path
:
class Info_Saver {
#define FORMAT_FFAT true
public:
// Needs implementation
Info_Saver(const char * Csv_File_Path);
void Save_Info(int Value_In);
void Format_Space();
void Delete_Parameter();
void Read_Parameter(char * Value_Out);
// Move this somewhere else?
void List_Dir(const char * Dir_Name, uint8_t levels);
private:
const char * m_Csv_File_Path;
};
如果成员变量(
m_Csv_File_Path
)和它们的行为你仍然不知道,前面描述的设计是一个公平的折衷。这种方法需要在调用站点做更多工作,因为您现在需要注意每个 CSV 文件都使用它们自己的 Info_Saver
对象。您还必须注意 m_Csv_File_Path
的生命周期不超过调用者的 Csv_File_Path
生命周期。