chipKIT® Development Platform

Inspired by Arduino™

adding (1) to a file name

Created Mon, 24 Feb 2014 14:38:40 +0000 by kaaasap


kaaasap

Mon, 24 Feb 2014 14:38:40 +0000

I am working with uC32 and mpide. I am trying to write a file. example: file.csv

if the file exists, I need to append to the file name (1) or (2) and so forth example: test(1).csv

I am using the SD ReadWrite example to start the process and I understand how it works. I understand how to check if the file exists, I just can't seem to get my head around how to append the (1) to the end of the file name.

I am thinking along the lines of:

myFile = SD.open(test.csv); if (test.csv == true) { for (i = 0; i < 99; i++) myFile = SD.open(test(1).csv, FILE_WRITE);
}

but of course I know its not that simple.

Any help would be greatly appreciated. Thank you!


majenko

Mon, 24 Feb 2014 15:42:22 +0000

You should look at the sprintf function.

Something along the lines of:

char filename[12];
int i = 0;

sprintf(filename, "test.csv");

while (fileExists(filename)) {
  i++;
  sprintf(filename, "test(%d).csv", i);
}

Note: fileExists() is just a placeholder function to whatever you need to check if the file exists (maybe write a little fileExists(char *filename) function to check the file existance for you).


kaaasap

Mon, 24 Feb 2014 18:14:31 +0000

deleted comment as it was an idiot responding


kaaasap

Mon, 24 Feb 2014 20:04:37 +0000

thank you majenko, you are the best!

if I could, I would buy you a round


kaaasap

Tue, 25 Feb 2014 14:53:32 +0000

why does it limit me to 8 characters for the file name?

char filename[100]; char timekeeper[12]; char datekeeper[12]; char testing[12]; sprintf(timekeeper, "%i:%i", hour, minute); sprintf(datekeeper, "%i_%i_%i", dayOfMonth, month, year); sprintf(testing, "delete_me"); int i = 0; sprintf(filename, "012345678.csv"); //// <--------here is where it limits me delay(5);

/while (SD.exists(filename)) { i++; sprintf(filename, "test(%i).csv", i); }/

int totalTests = 1234; char testsBuffer[50];

sprintf(testsBuffer, "Total Tests %i", totalTests);

// open the file. note that only one file can be open at a time, // so you have to close this one before opening another. myFile = SD.open(filename,FILE_WRITE); delay(200);

//if the file opened okay, write to it:
if (myFile) {
  Serial.print("Writing to .csv...");
  myFile.print(testsBuffer);
  myFile.println("   ");
  myFile.println("   ");
  myFile.println("   ");
  myFile.println("   ");
  myFile.println("   ");

  //close the file:
  myFile.close();
  Serial.println("done.");
} 
else {
  //if the file didn't open, print an error:
  Serial.println("error opening");
}

//re-open the file for reading:
myFile = SD.open(filename);
if (myFile) {
  Serial.println(filename);

  //read from the file until there's nothing else in it:
  while (myFile.available()) {
    Serial.write(myFile.read());
  }
  //close the file:
  myFile.close();
} 
else {
  //if the file didn't open, print an error:
  Serial.println("error opening.csv");
}

} void loop() { // nothing happens after setup }


majenko

Tue, 25 Feb 2014 15:58:02 +0000

They are what are called "8.3" filenames, and have been the standard filename format since CP/M and right up to Windows 95, and even then under the hood the files are actually stored as "munged" 8.3 filenames.

[url]http://en.wikipedia.org/wiki/8.3_filename[/url]

It's basically due to the fact that the filesystem only has enough room in each directory entry to store 8 characters of filename and 3 letters of extension. That is why so many files have a 3-letter extension (.txt, .doc, .exe, .com, .bat, .vbs, .xls, etc).


kaaasap

Tue, 25 Feb 2014 16:02:08 +0000

awesome lol

so I will have to convert from long to short then add ~1, ~2, etc. to the end

again, thank you majenko


kaaasap

Fri, 28 Feb 2014 19:11:21 +0000

I have been trying to find info on how to capture the file created/last modified date and time.

example: file name created last modified myfile.txt 2/28/2014 2/28/2014

Does anyone have a sample or know of a tutorial for this?


Jacob Christ

Fri, 28 Feb 2014 19:44:41 +0000

File->Examples->SD->Card Info


majenko

Fri, 28 Feb 2014 19:50:11 +0000

You want to use the dirEntry() function of the SdFile object.

Something along the lines of:

dir_t dent;

if (myFile.dirEntry(&amp;dent)) {
  Serial.println(dent.lastWriteDate);
  Serial.println(dent.lastWriteTime);
}

Comments in the FatStructs.h file say:

* Date Format. A FAT directory entry date stamp is a 16-bit field that is
 * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
 * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
 * 16-bit word):
 *  
 * Bits 9-15: Count of years from 1980, valid value range 0-127
 * inclusive (1980-2107).
 *  
 * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
 *
 * Bits 0-4: Day of month, valid value range 1-31 inclusive.
 *
 * Time Format. A FAT directory entry time stamp is a 16-bit field that has
 * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
 * 16-bit word, bit 15 is the MSB of the 16-bit word).
 *  
 * Bits 11-15: Hours, valid value range 0-23 inclusive.
 *
 * Bits 5-10: Minutes, valid value range 0-59 inclusive.
 *     
 * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
 *  
 * The valid time range is from Midnight 00:00:00 to 23:59:58.

kaaasap

Fri, 28 Feb 2014 21:25:06 +0000

Thank you majenko and Jacob

Naturally, the one place I didn't look. Such a fool. I guess that is why the authors took the time to write those notes.......


GrahamM242

Sat, 01 Mar 2014 16:12:49 +0000

You should look at the sprintf function. Something along the lines of:

char filename[12];
sprintf(filename, "test.csv");

A plea here - if you can help it, please don't use sprintf! Use snprintf instead - it works almost exactly the same way, but requires you to specify the maximum length of the buffer it'll write to. This removes the risk of a buffer overflow screwing up your code when you're not expecting it. Effectively the code would become:

char filename[12];
snprintf(filename, sizeof(filename),"test.csv");

kaaasap

Fri, 07 Mar 2014 22:09:36 +0000

sorry majenko and jacob, I am trying to set the date and time of the file creation.


Jacob Christ

Sat, 08 Mar 2014 16:57:04 +0000

I've never tried this, but I found a thread here that may be applicable:

http://forum.arduino.cc/index.php?topic=72739.0

Jacob


kaaasap

Mon, 10 Mar 2014 12:54:18 +0000

OOOOH!! Good find Jacob. I am working on it now. Again, many thanks.


kaaasap

Mon, 10 Mar 2014 13:44:42 +0000

Here is a copy of the my testing file. Please ignore some of the randomness in it.

#include <SD.h> #include "Wire.h" #include <RTClib.h>

File myFile; const uint8_t SD_CS = 4; // SD chip select RTC_DS1307 RTC; // define the Real Time Clock object

// Default SD chip select const int chipSelect_SD_default = 4;

// chipSelect_SD can be changed if you do not use default CS pin const int chipSelect_SD = chipSelect_SD_default;

//*Begin Real Time Clock///

#define DS1307_I2C_ADDRESS 0x68 // This is the I2C address // Arduino version compatibility Pre-Compiler Directives #if defined(ARDUINO) && ARDUINO >= 100 // Arduino v1.0 and newer #define I2C_WRITE Wire.write #define I2C_READ Wire.read #else // Arduino Prior to v1.0 #define I2C_WRITE Wire.send #define I2C_READ Wire.receive #endif

// Global Variables int command = 0; // This is the command char, in ascii form, sent from the serial port
long previousMillis = 0; // will store last time Temp was updated byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; byte test; byte xero; char *Day[] = { "","Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; char *Mon[] = { "","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; int sethour, setminute, setmonth, setdayofmonth, setyear;

// Convert normal decimal numbers to binary coded decimal byte decToBcd(byte val) { return ( (val/10*16) + (val%10) ); }

// Convert binary coded decimal to normal decimal numbers byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); }

// 1) Sets the date and time on the ds1307 // 2) Starts the clock // 3) Sets hour mode to 24 hour clock // Assumes you're passing in valid numbers, Probably need to put in checks for valid numbers.

void setDateDs1307()
{ hour = sethour; minute = setminute; month = setmonth; dayOfMonth = setdayofmonth; year = setyear;

Wire.beginTransmission(DS1307_I2C_ADDRESS); I2C_WRITE(xero); I2C_WRITE(decToBcd(second) & 0x7f); // 0 to bit 7 starts the clock I2C_WRITE(decToBcd(minute)); I2C_WRITE(decToBcd(hour)); // If you want 12 hour am/pm you need to set // bit 6 (also need to change readDateDs1307) I2C_WRITE(decToBcd(dayOfWeek)); I2C_WRITE(decToBcd(dayOfMonth)); I2C_WRITE(decToBcd(month)); I2C_WRITE(decToBcd(year)); Wire.endTransmission(); }

void getDateDs1307() { // Reset the register pointer Wire.beginTransmission(DS1307_I2C_ADDRESS); I2C_WRITE(xero); Wire.endTransmission();

Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

// A few of these need masks because certain bits are control bits second = bcdToDec(I2C_READ() & 0x7f); minute = bcdToDec(I2C_READ()); hour = bcdToDec(I2C_READ() & 0x3f); // Need to change this if 12 hour am/pm dayOfWeek = bcdToDec(I2C_READ()); dayOfMonth = bcdToDec(I2C_READ()); month = bcdToDec(I2C_READ()); year = bcdToDec(I2C_READ());

sethour = hour; setminute = minute; setmonth = month; setdayofmonth = dayOfMonth; setyear = year;

}

//------------------------------------------------------------------------------ // call back for file timestamps void dateTime(uint16_t* date, uint16_t* time) { DateTime now = RTC.now();

// return date using FAT_DATE macro to format fields *date = FAT_DATE(now.year(), now.month(), now.day());

// return time using FAT_TIME macro to format fields *time = FAT_TIME(now.hour(), now.minute(), now.second()); }

void setup() { int buff; unsigned int check[buff]; char settingsBuffer1[72]; char settingsBuffer2[72]; char settingsBuffer3[72]; char settingsBuffer4[72]; char settingsBuffer5[72]; char settingsBuffer6[72]; char settingsBuffer7[72]; char settingsBuffer8[72]; char settingsBuffer9[72]; char settingsBuffer10[72]; char settingsBuffer11[72]; char settingsBuffer12[72]; char settingsBuffer13[72]; char settingsBuffer14[72]; char settingsBuffer15[72]; char settingsBuffer16[72]; char settingsBuffer17[72]; char settingsBuffer18[72]; char settingsBuffer19[72]; char settingsBuffer20[72]; char settingsBuffer21[72]; char settingsBuffer22[72];

Serial.begin(9600); Wire.begin();

Serial.print("Initialixing SD card...");

pinMode(chipSelect_SD_default, OUTPUT); digitalWrite(chipSelect_SD_default, HIGH);

pinMode(chipSelect_SD, OUTPUT); digitalWrite(chipSelect_SD, HIGH);

if (!SD.begin(chipSelect_SD)) { Serial.println("initialixation failed!"); return; } Serial.println("initialixation done.");

char filename[50]; int num = 22; char testName[num]; int i = 0; int y = 1; int currentScale = 1; char scaleBuffer[3]; double loadLock = 12.97; char loadBuffer[6]; double timeLoad = 9999; char timeBuffer[5]; String testname = "AAAAAAAAAAAAAAAAAAAAA"; sprintf(filename, "setup.csv");

while (SD.exists(filename)) { SD.remove(filename); }

SdFile::dateTimeCallback(dateTime);

// open the file. note that only one file can be open at a time,

// so you have to close this one before opening another. myFile = SD.open("setup.csv",FILE_WRITE); delay(200);

//if the file opened okay, write to it:

if (myFile) { myFile.print("Current Scale_"); myFile.println(currentScale); //current scale myFile.println(" "); myFile.print("Load Lock_"); myFile.println(loadLock); //load lock on or off myFile.println(" ");

	//close the file:
myFile.close();
Serial.println("done.");

} else { //if the file didn't open, print an error: Serial.println("error opening"); }

//re-open the file for reading: myFile = SD.open("setup.csv"); if (myFile) { //Serial.println("setup.csv");

 //read from the file until there's nothing else in it:
while (myFile.available()) {
  check[buff] = (myFile.read());
//Serial.println(check[buff]);
if (check[buff] == 95)
{
  settingsBuffer1[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer2[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer3[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer4[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer5[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer6[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer7[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer8[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer9[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer10[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer11[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer12[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer13[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer14[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer15[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer16[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer17[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer18[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer19[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer20[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer21[i] = myFile.read();
  delayMicroseconds(10);
  settingsBuffer22[i] = myFile.read();
  delayMicroseconds(10);
  i++;
}      
}

//close the file:
myFile.close();

} else { //if the file didn't open, print an error: Serial.println("error opening.csv"); } Serial.println("Done");

}

void loop() { // nothing happens after setup }


kaaasap

Mon, 10 Mar 2014 13:45:19 +0000

it works great at creating a file with the created on and last modified date.


kaaasap

Thu, 03 Apr 2014 14:43:41 +0000

when I save the test name to the SD card, and then read it back on start up, a 'space' and 'carraige return' are appended to the end. The test name goes from: testName.csv

to testName(space) (space).csv


kaaasap

Thu, 03 Apr 2014 15:20:22 +0000

ah, println adds the \n and I am picking up a (space).

strchr search and clip idea might work...


kaaasap

Thu, 24 Apr 2014 14:00:31 +0000

Now that I am writing and reading the files correctly, I am trying to read all file names, ls_date and ls_time and save into an array. I want to be able to display four files w/time stamps on my 4D systems display.
I found the following example:

#include <SD.h>

// set up variables using the SD utility library functions: Sd2Card card; SdVolume volume; SdFile root;

const int chipSelect_SD_default = 10; // Change 10 to 53 for a Mega

const int chipSelect_SD = chipSelect_SD_default;

void setup() { Serial.begin(9600); Serial.print("\nInitializing SD card...");

pinMode(chipSelect_SD_default, OUTPUT); digitalWrite(chipSelect_SD_default, HIGH);

pinMode(chipSelect_SD, OUTPUT); digitalWrite(chipSelect_SD, HIGH);

if (!card.init(SPI_HALF_SPEED, chipSelect_SD)) { Serial.println("Error"); return; } else { Serial.println("Loading..."); }

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 if (!volume.init(card)) { Serial.println("No files"); return; }

Serial.println("Files"); root.openRoot(volume);

// list all files in the card with date and size root.ls(LS_R | LS_DATE | LS_SIZE); }

void loop(void) {

}

But I am not able to store anything as the .h file has this

void SdFile::ls(uint8_t flags, uint8_t indent) { dir_t* p;

rewind(); while ((p = readDirCache())) { // done if past last used entry if (p->name[0] == DIR_NAME_FREE) break;

// skip deleted entry and entries for . and  ..
if (p-&gt;name[0] == DIR_NAME_DELETED || p-&gt;name[0] == '.') continue;

// only list subdirectories and files
if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;

// print any indent spaces
for (int8_t i = 0; i &lt; indent; i++) Serial.print(' ');

// print file name with possible blank fill
printDirName(*p, flags &amp; (LS_DATE | LS_SIZE) ? 14 : 0);

// print modify date/time if requested
if (flags &amp; LS_DATE) {
   printFatDate(p-&gt;lastWriteDate);
   Serial.print(' ');
   printFatTime(p-&gt;lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(p) &amp;&amp; (flags &amp; LS_SIZE)) {
  Serial.print(' ');
  Serial.print(p-&gt;fileSize);
}
Serial.println();

// list subdirectory content if requested
if ((flags &amp; LS_R) &amp;&amp; DIR_IS_SUBDIR(p)) {
  uint16_t index = curPosition()/32 - 1;
  SdFile s;
  if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
  seekSet(32 * (index + 1));
}

} }

it directly prints everything.

Any suggestions or tips are very appreciated.

Thank you.


kaaasap

Mon, 28 Apr 2014 14:10:20 +0000

I am using the following code to capture the file names when reading them from the uSD card, but I am having trouble saving the names to an array. What I have come up with so far only saves the last file name into the [0] location. Here is a copy of my code. Any suggestions would help.

#include <SD.h>

File root;

char fileName[21]; char fileName1[21]; char fileName2[21]; char fileName3[21]; int counter; int stamp; char* storefileName[200]; char* capturefileName[200];

void setup() { //genieBegin(GENIE_SERIAL, 9600); //Serial at 9600 baud for display Serial.begin(9600); pinMode(10, OUTPUT);

SD.begin(10);

root = SD.open("/"); }

void loop() { printDirectory(root, 0);

if(counter < 4) { Serial.println("done!"); //Serial.println(captureFilename); Serial.println("restart"); } else if(counter == 4) { sprintf(fileName, capturefileName[1]); Serial.println(fileName); sprintf(fileName1, capturefileName[2]); Serial.println(fileName1); sprintf(fileName2, capturefileName[3]); Serial.println(fileName2); sprintf(fileName3, capturefileName[4]); Serial.println(fileName3); Serial.println("printed fileName"); counter = 0; }; }

void printDirectory(File& dir, int numTabs) { while(true && counter <= 3) {

File entry =  dir.openNextFile();
if (! entry)
{
  // no more files
  Serial.println("**nomorefiles**");
  counter = 5;
}
else 
{
  storefileName[stamp] = entry.name();
  capturefileName[stamp] = storefileName[stamp];
  Serial.println(storefileName[stamp]);
  Serial.println(counter,DEC);
  Serial.println(stamp,DEC);
}
counter++;
stamp++;

}; }

Thank you.


kaaasap

Mon, 28 Apr 2014 18:28:07 +0000

I almost have it. I have created a vector of Strings.

Vector<String> filefinder; for (int num = 0; num < 512; ++num) { //boolean isfilefinder = true; for (size_t idx = 0; idx < filefinder.size(); ++idx) filefinder.push_back(num); filefinder[num] = tempfileName; /while(filecounter <= filefinder.size()) { //Serial.println(prime[counter]); filecounter++; if(filecounter == filefinder.size()) { //Serial.println(""); filecounter = 0; break; } }/ //delay(1000); } sprintf(fileName, "%s", filefinder[0]); genieWriteStr(37, fileName); } but I am getting the following error: error: cannot pass objects of non-trivially-copyable type 'class String' through '...'