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 – DataFiddler Apr 30 '20 at 8:48
  • @DataFiddler I'm using SdFat.h with Long Names (which allows names up to 255 characters) – Sleb Lagnej Apr 30 '20 at 9:14
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? – Sleb Lagnej Apr 30 '20 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. – Sleb Lagnej Apr 30 '20 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 – Sleb Lagnej Apr 30 '20 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 – Sleb Lagnej Apr 30 '20 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) – Sleb Lagnej Apr 30 '20 at 14:58
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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