SdFat creating a file does not work

In my function I am trying to create a new file on the SdCard. I am opening the directory with:

dirObj.open(directory, O_RDONLY)

where, dirObj is an object of type 'File' (alias of SdFile) and directory is a char array that stores the directory name. The file itself is being created with:

if (markFile.open(&dirObj, fname, (O_CREAT))) {
  // Do something
}else{
  // Return an error
}

where markFile is an object of type File and fname is a char array containing the the file to be created. It is a long file name and I am using SdFat v2 so it should be supported. The file is never created and the error is always returned so the open() method is returning False.

SdFat has two other methods for opening a file, using a full path, or just the filename, the latter of which should create the file in the current directory. How is the curent directory determined? Must dirObj be open? . I have tried all options but neither seems work. Didn't think creating a file would be this troublesome.....

Perhaps you should close the file, or write a record and then close the file.
Paul

Paul, thanks. I have tried adding sync(0 and close(0) after the open(), but it made no difference. This function should not write to the file. It just needs to create a file on the media. Writing and reading activity is done elsewhere.

if you open the directory in read only mode, then you might not be able to create a file in that directory.

Had that thought as well and what you say seems logical, but this is what the documentation says:

Note:

Directory files must be opened read only. Write and truncation is not allowed for directory files.

Documentation (Doxygen style summary) here:
https://www.if.ufrj.br/~pef/producao_academica/artigos/audiotermometro/audiotermometro-I/bibliotecas/SdFat/Doc/html/class_sd_base_file.html#a6ff5b48f672515ec20831583de74407f

I did try opening the directory with O_RDRW but it made no difference.

I have just tried a modified an simplified example based on ReadCsvFile. This also does not work and has the same problem. I have removed the parser as it is not required, reduced the SD config at the beginning to its basic elements and added a couple more prompts to get some feedback on what is happening, but the structure of the file, particularly the setup() section is otherwise the same.

#include "SdFat.h"

// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 0
/*
  Change the value of SD_CS_PIN if you are using SPI and
  your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/

// SDCARD_SS_PIN is defined for the built-in SD on some boards.
const uint8_t SD_CS_PIN = 4;

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
#endif  // HAS_SDIO_CLASS


SdFat sd;
File file;

char line[40];

//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
// Check for extra characters in field or find minus sign.
char* skipSpace(char* str) {
  while (isspace(*str)) str++;
  return str;
}


//------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);

  // Wait for USB Serial
  while (!Serial) {
    yield();
  }
  Serial.println("Type any character to start");
  while (!Serial.available()) {
    yield();
  }
  // Initialize the SD.
  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
    return;
  }
  // Remove any existing file.
  if (sd.exists("Test2.txt")) {
    Serial.println(F("File exists - removing..."));
    sd.remove("Test2.txt");
    Serial.println(F("Removed."));
  }

  // Create the file.
  if (!file.open("Test.txt", FILE_WRITE)) {
    error("open failed");
  }else{
    Serial.println(F("File created."));
  }
/*
  // Create the file.
  if (!file.open("Test.txt", O_CREAT)) {
    error("open failed");
  }else{
    Serial.println(F("File created."));
  }
*/

  // Write test data.
  file.print(F(
    "abc,123,456,7.89\r\n"
    "def,-321,654,-9.87\r\n"
    "ghi,333,0xff,5.55"));

  // Rewind file for read.
  file.rewind();

  while (file.available()) {
    int n = file.fgets(line, sizeof(line));
    if (n <= 0) {
      error("fgets failed");
    }
    if (line[n-1] != '\n' && n == (sizeof(line) - 1)) {
      error("line too long");
    }
    Serial.println();
  }
  file.close();
  Serial.println(F("Done"));
}

void loop() {
}

I can't check right now but if you do something like this

SD.remove("test.bin");
File markFile = SD.open("test.bin", FILE_WRITE);
markFile.close();

would you get an empty "test.bin" file ?

An interesting idea to refer to the SD class object rather than the file object since it also contains the .remove() and open() methods. I tried it, but it still fails. I did include the remove as per suggestion to ensure that there was no file of that name already present.

I wish there was an error code instead of just a bool true or false to indicate the reason for the failure!

Damned... oh well, that was an idea. nothing else comes to mind at this time

I think I have solved it. When using the somewhat modified example program above, the FILE_WRITE flag was used in the open() method as per original example. After sorting out a hardware problem with the CS pin (I had a USBASP programmer connected to the m1284p dev board which uses pin 4 by default and I eventually changed the SD card to use pin 3) this did then work.

Once that stage was reached, I swapped FILE_WRITE to O_CREAT again and once again it failed to create the file. I then combined O_CREAT | O_AT_END and finally O_RDWR | O_CREAT | O_AT_END. It worked only when all three flags were combined. As it turns out, this is equivalent to using FILE_WRITE. The SdFat documentation refers only to the individual O_ flags and my initial use of O_CREAT alone was obviously insufficient.

The original problem arose from insufficient flags being used in the open() method. The secondary problem with the example test script was a result of a hardware issue with the alternate test setup being used for that test.

Good
Thx for documentating the solution

I'm SO glad to hear that you had this problem (and solved it). I've been tearing my hair out trying to find why I couldn't create a file on the SD using the O_CREAT flag.

Opening as FILE_WRITE works. I now have to see if I can write randomly in the file as that was my reason for using the SdFat library.

And I just found this https://stackoverflow.com/questions/21155803/error-when-writing-to-file-after-opening-it-with-o-append-o-create on Stackoverflow. It seems that 'O_CREAT 'is a modifier for O_RDONLY , O_WRONLY and O_RDWR. I'll try this out tomorrow too.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.