Renaming files on the SD card

I've looked through the SD library for IDE 0022 but did not see a function which renames the file on the SD card. Does anybody know how to rename SD card files or if there is another library out there which can?

I'm wanting to keep the last full day's data onto the SD card, always calling it yesturda.csv

So, when there is yesturda.csv with 24 hrs of data, then I create now.csv to start writing the next day's data. When now.csv fills up 24 hours with of data, then I'll want to delete yesturda.csv and rename now.csv to yesturda.csv. The next 24 hours starts again with a new now.csv.

As you can see, all I need is a file rename command. Any ideas? Thanks.

Haven't looked into the standard library very much yet, but I do know the SDFat library renames files perfectly. I think it's a great piece of work.

http://code.google.com/p/sdfatlib/

I've already written my cude using the standard SD library and was noping not to change all the syntax for SdFat. Does anyone know how to add the rename feature from SdFAT into the standard SD library?

There is no practical way to add rename to SD.h. SD.h is a wrapper for an old version of SdFat that does not support rename.

The newer SdFat with rename can't be used with the SD.h wrapper.

This is unfortunate. Does anybody know when an updated IDE-standard SD library will exist with a rename feature?

Does anybody know the equivalent of this SD code using SdFat?

//if logfile.txt doesn't exist, SD.open creates a new file, if it exists, it appends data to it
  File dataFile = SD.open("logfile.txt", FILE_WRITE);  
  if (dataFile) {    // If the file is available, write to it
    dataFile.println("Hello");
    dataFile.close();
    }

How do I create this same functionality from SdFat?

Also, what is the equivalent of,

if (SD.exists("now.csv"))

?

To open or create a file for append in SdFat

  if (datafile.open("logfile.txt", O_WRITE | O_CREAT | O_APPEND)) {
    dataFile.println("Hello");
    dataFile.close();
  }

If you declared

SdFat sd;

use

  if (sd.exists("now.csv"))

When I do that I get,

error: 'class Sd2Card' has no member named 'exists'

I said esists() is a member of the class SdFat, not Sd2Card.

I'm not sure I follow. I am including SdFat.h already. What else do I need to include to get exists() to function?

EDIT: The last features I need for the transition from SD to SdFat is the equivalent of this,

 if (card.exists("now.csv")) {
   now.remove("now.csv");
  }

Read the html documentation and look at examples.

The documentation is horrific.

Maybe somebody else here would like to exercise their skills of generocity?

O.K. here is a sketch that checks for "myfile.txt".

#include <SdFat.h>
SdFat sd;
const uint8_t CHIP_SELECT = 10;  // pin 10 is SD chip select
void setup() {
  Serial.begin(9600);
  if (!sd.init(SPI_HALF_SPEED, CHIP_SELECT)) sd.initErrorHalt();
  if (sd.exists("myfile.txt")) Serial.println("it exists");
}
void loop() {}

Thank you for sharing this information. I now see what you mean by the SdFat class. I had "sd" as part of another class in my code.

While I can use the SdFat lib code to perform all my desired SD writing needs (in stand-alone sketches), it seems when I integrate it with all my other code the SD card isn't being written to. It is probably not initializing at all.

I'm at a 25000 byte sketch size and am constantly trying to optimise code to save SRAM space. Any new additions I make often set the Arduino into a resetting mode (implying I'm out of SRAM space), so I suspect that using SdFat over the SD class caused me to run out of SRAM.

Has there been any development towards introducing a renaming feature into the next IDE release for the SD class?

Maybe there is another way to accomplish what I want with just the 0022 SD library.

As I mentioned, I'm wanting to keep the last full day's worth data onto the SD card, always calling it yesturda.csv

So, when there is yesturda.csv with 24 hrs of data, then I create now.csv to start writing the next day's data. When now.csv fills up 24 hours with of data, then I'll want to delete yesturda.csv and rename now.csv to yesturda.csv. The next 24 hours starts again with a new now.csv.

Is there another way to always have yesturday's data on a static filename? Thanks.

SD.h will not have rename anytime soon. In Arduino 1.0 SD.h will be about two KB larger than the new SdFat and use more RAM.

You can do anything SD.h does with SdFat since SD.h is a simple wrapper for an old version of SdFat. The SD.h wrapper mainly changes the default behavior for open(), and uses a different syntax for the API.

SD.h opens files so sync/flush is called after every write()/print(). This is very slow but insures data is written to the SD. Also SD.h positions files opened for write at EOF.

Try opening your file with the flags in this sketch:

#include <SdFat.h>
#include <SdFatUtil.h>
SdFat sd;

SdFile logfile;

// open like SD.h
const uint8_t OPEN_FLAGS = O_RDWR | O_CREAT | O_SYNC | O_AT_END;

const uint8_t SD_CHIP_SELECT = 10;

#define error(msg) sd.errorHalt_P(PSTR(msg))

void setup() {
  Serial.begin(9600);
  Serial.println("type any character to start");
  while (Serial.read() < 0);
  
  // initialize SdFat
  if (!sd.init(SPI_FULL_SPEED, SD_CHIP_SELECT)) sd.initErrorHalt();
  
  // use SD.h style flags
  if (!logfile.open("now.csv", OPEN_FLAGS)) error("open");
  
  // add a line to file
  logfile.println("line added to logfile");
  
  // skip sync and close to prove data is saved
  Serial.println("Done");
}
void loop() {}

Ok. I will try this. To improve my understanding, could you point me to the documentation that states the functionality of all possible open flags? So far, I've seen:

0_RDWR
0_CREAT
0_SYNC
0_AT_END
0_WRITE
0_APPEND

You need to read the html documentation. Click on the classes tab. Select the SdFile class. Look at open().

Here is what you would find for open flags

[in] oflag Values for oflag are constructed by a bitwise-inclusive OR of flags from the following list

O_READ - Open for reading.

O_RDONLY - Same as O_READ.

O_WRITE - Open for writing.

O_WRONLY - Same as O_WRITE.

O_RDWR - Open for reading and writing.

O_APPEND - If set, the file offset shall be set to the end of the file prior to each write.

O_AT_END - Set the initial position at the end of the file.

O_CREAT - If the file exists, this flag has no effect except as noted under O_EXCL below. Otherwise, the file shall be created

O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.

O_SYNC - Call sync() after each write. This flag should not be used with write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. These functions do character at a time writes so sync() will be called after each byte.

O_TRUNC - If the file exists and is a regular file, and the file is successfully opened and is not read only, its length shall be truncated to 0.

Thank you for this. But still, I still cannot get SdFat to work like SD for whatever reason. While it works in the initial setup() it fails in loop(). It cannot seem to open or write to an SD file and even ListFiles(client, LS_SIZE) fails to list the existing files on the SD card. When switching back to SD lib, everything works.

Maybe the problem is obvious to you, or maybe I'm out of RAM. The program doesn't hang though, it still continues to print to HTTP, but ListFIles doesn't work and nothing gets written to the card.

Code split into two continuous pieces as follows:

#include <Wire.h>
#include <SdFat.h>
#include <SPI.h>
#include <Ethernet.h>

Sd2Card card;
SdFat sd;
SdVolume volume;
SdFile root;
SdFile file;
SdFile dataFile;
SdFile now;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
byte ip[] = { 192,168,1,20 }; 

Server server(80); 

void setup() {

  if (!sd.init(SPI_HALF_SPEED, 4)) sd.initErrorHalt(); 
  volume.init(&card);             
  root.openRoot(&volume);
  Ethernet.begin(mac, ip); 
  server.begin();  

}
  //HTTP Server
  
  char clientline[40];  
  int index = 0;

  Client client = server.available();  
  if (client) {  
    boolean current_line_is_blank = true; 
    index = 0;  
    
    while (client.connected()) {  
      if (client.available()) {  
        char c = client.read(); 
        
        if (c != '\n' && c != '\r') {  
          clientline[index] = c; 
          index++;  
          if (index >= 40)  
            index = 40 - 1;  
          continue;  
        }
             
        clientline[index] = 0; 
                
        if (strstr(clientline, "GET / ") != 0) { 
          client.println("HTTP/1.1 200 OK");    
          client.println("Content-Type: text/html");
          client.println();
          client.print("<!DOCTYPE html>");
          client.print("Hello");
          client.println();
          client.println("<h3>Files:</h3>"); 

          ListFiles(client, LS_SIZE);

          client.print("</html>");
      } 
        
      else if (strstr(clientline, "GET /") != 0) {  
        char *filename;
          
        filename = clientline + 5; 
        (strstr(clientline, " HTTP"))[0] = 0;

        if (! file.open(&root, filename, O_READ)) { 
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File Not Found!</h2>");
          break;  
        }
        
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/plain");
        client.println();
          
        int16_t c;
        while ((c = file.read()) > 0 ) {  
            client.print((char)c);
        }
          
        file.close();
      } 
      else {  
        client.println("HTTP/1.1 404 Not Found");
        client.println("Content-Type: text/html");
        client.println();
        client.println("<h2>File Not Found!</h2>");
      }
      break;  
    }  
  }
    delay(100); 
    client.stop();
  }
}

void ListFiles(Client client, uint8_t flags) {
  dir_t p; 
  root.rewind();
  client.println("<ul>");
  while (root.readDir(p) > 0) {
    if (p.name[0] == DIR_NAME_FREE) break;
    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
    if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
    client.print("<li><a href=\"");
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    client.print("\">");
    for (uint8_t i = 0; i < 11; i++) {
      if (p.name[i] == ' ') continue;
      if (i == 8) {
        client.print('.');
      }
      client.print(p.name[i]);
    }
    client.print("</a>");
    if (DIR_IS_SUBDIR(&p)) {
      client.print('/');
    }
    if (flags & LS_DATE) {
       root.printFatDate(p.lastWriteDate);
       client.print(' ');
       root.printFatTime(p.lastWriteTime);
    }
    if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
      client.print(' ');
      client.print(p.fileSize);
    }
    client.println("</li>");
  }
  client.println("</ul>");
}