0

I'm using the SdFat.h library on a STM32 and I can successfully create a file in the root directory using SD.open("test.txt", FILE_WRITE); but my code fails to create SD.open("DATA/data_test.txt", FILE_WRITE); in a directory. Here's the piece of code that successfully creates a file in the root:

String final_book_name = upload_book_name + ".txt";
if (SD.exists(final_book_name.c_str())) {
  SD.remove(final_book_name.c_str());
}
tft.println(final_book_name); // This successfully prints "test.txt"
book_file = SD.open(final_book_name, FILE_WRITE);
if (SD.exists(final_book_name.c_str())) {
  tft.print("Created file");
} else {
  tft.print("Failed to create/replace\nfile!");
}

and here's the piece of the code that fails to create a file in a directory:

if (!SD.exists(DATA_DIR)) {
  SD.mkdir(DATA_DIR);
}
String final_book_name = upload_book_name + ".txt";
String book_data_path = DATA_DIR;
book_data_path += "/data_" + final_book_name;
if (SD.exists(book_data_path.c_str())) {
  SD.remove(book_data_path.c_str());
}
tft.println(book_data_path); // This successfully prints "DATA/data_test.txt"
File book_data_file = SD.open(book_data_path, FILE_WRITE);
if (SD.exists(book_data_path.c_str())) {
  book_data_file.print(upload_book_font);
  book_data_file.print("|");
  book_data_file.print("0");
  book_data_file.close();
} else{
  tft.print("Failed to create/replace\ndata file!");
  if (SD.exists(final_book_name.c_str())) {
    SD.remove(final_book_name.c_str());
  }
}
2
  • 1
    Try it with /DATA/test.txt I remember SD library uses the classic 8.3 filenames and data_test.txt is invalid Commented Apr 30, 2020 at 8:48
  • @DataFiddler I'm using SdFat.h with Long Names (which allows names up to 255 characters) Commented Apr 30, 2020 at 9:14

2 Answers 2

1

I found the issue. I'm not creating the directory folder properly. When I checked the SD card from another device, the DATA folder was invalid, and creating it manually works. I'll look for a solution and post an update.

UPDATE: https://forum.arduino.cc/index.php?topic=421131.0 I'll try this tomorrow but it'll probably fix the issue.

0

As you have given no variable for DATA_DIR

String book_data_path = DATA_DIR;
book_data_path += "/data_" + final_book_name;

so your resulting path looks like

DATA_DIR + "/data_" + final_book_name

IF DATA_DIR = "/" then it would be "/" + "/data_" + final_book_name

As tip do not use the string class but char arrays

definition

 const char[] DATA_DIR = "/books";  
 char book_data_path [128] = {'\0'};
 char final_book_name [13] =  {'\0'}; // IF no LFN support is used its 8.3 !!!
 const char upload_book_name[] = "my_book";
 strcpy (final_book_name, upload_book_name);
 strcat (final_book_name, ".txt");
 Serial.println(final_book_name);

If you want long filr namesupport us SDFat library or enable LFB withSD lib (whichneeds about 35% ,ore memory as SDfat (when using long file names).
EDIT
As you are using SDFat and I do not know which version/fork there is abug with writing to subdirectories. Please check the following:
To check run the SdFat\examples\DirectoryFunctions and watch your serial monitor for the results
SdFile.cpp. At line 782 and 1452, you have (in my version):

if (block <= m_vol->cacheBlockNumber()
  && block < (m_vol->cacheBlockNumber() + nb)) {

The working code has:

if (m_vol->cacheBlockNumber() <= block
  && block < (m_vol->cacheBlockNumber() + nBlock)) {

If you have the upper version change it and it should work
EDIT 2 Work around for buggy SDFat lib
Here is a workaround code

const char DATA_DIR [] = "data";
char final_book_name[128] ={'\0'};
char book_data_path [256] ={'\0'};

if (!SD.exists(DATA_DIR)) {
  SD.mkdir(DATA_DIR);
  SD.chdir(DATA_DIR);
}

strcpy (final_book_name, upload_book_name);
 strcat (final_book_name, ".txt";
String book_data_path = DATA_DIR;

strcpy(book_data_path, "data_");
strcat(book_data_path, final_book_name);

if (SD.exists(book_data_path)) {
  SD.remove(book_data_path);
}
SD.mkdir(book_data_path);
SD.chdir(book_data_path);

tft.println(DATA_DIR);
tft.println(book_data_path); // This successfully prints "DATA/data_test.txt"
File book_data_file = SD.open(final_book_name, FILE_WRITE);
if (SD.exists(final_book_name)) {
  book_data_file.print(upload_book_font);
  book_data_file.print("|");
  book_data_file.print("0");
  book_data_file.close();
} else{
  tft.print("Failed to create/replace\ndata file!");
  if (SD.exists(final_book_name)) {
    SD.remove(final_book_name);
  }
}
9
  • DATA_DIR is "DATA". I don't see the solution in your answer. I will make my Strings to characters, that's a good idea but what about my main issue here? Commented Apr 30, 2020 at 10:55
  • Sorry, it's still unclear to me what I should do. I'm using STM32, not an Arduino and I don't have a Serial Monitor. I will try downloading a newer SdFat version. Commented Apr 30, 2020 at 13:48
  • I downloaded the newest version of SdFat from here: github.com/greiman/SdFat and ran it, but it still fails to create a file in a subdirectory Commented Apr 30, 2020 at 14:29
  • I could try to do SD.chdir(DATA_DIR); but I'm not sure how that works exactly and if even that's the problem. I don't think SD.chdir(DATA_DIR); is necessary Commented Apr 30, 2020 at 14:43
  • I tried with SD.chdir(DATA_DIR); (as far as I know how to use it) but it failed. (it created the file in the root, not in the dir) Commented Apr 30, 2020 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.