Conflict between SdFat and Streaming libraries

I want to use the << operator from Mikal Hart's Streaming library (Streaming | Arduiniana) to write strings into files on the SD card. This works fine with the default SD library, but I'm having trouble using it with the SdFat library.

If I try to include Streaming.h in a sketch with SdFat.h, I get errors:

#include <SPI.h>
//#include <Streaming.h> // compiler hangs
#include <SdFat.h>
//#include <Streaming.h> // compiler throws an error

void setup() {}
void loop() {}

It looks like SdFat is also defining the "<<" operator. But if I try to use it like this (as if I had included Streaming.h), the compiler hangs:

#include <SPI.h>
//#include <Streaming.h> // compiler hangs
#include <SdFat.h>
//#include <Streaming.h> // compiler throws an error

void setup() 
{
  Serial.begin(9600);
  Serial << "howdy";     // compiler hangs
}
void loop() {}

What do I need to do? Did I miss some important documentation?

After looking at code examples and doing some Google searches, I was led to this piece of example code included with SdFat:

https://github.com/greiman/SdFat/tree/master/SdFat/examples/cin_cout

The trick seems to be declaring streaming objects of class ArduinoOutStream, and using those objects instead of directly using Serial or an SD file object (like Streaming.h lets you do).

There's some Doxygen-generated documentation in the SdFat html folder. The filename is class_arduino_out_stream.html, but it didn't mean much to me, a C++ novice.

I got my code to work by following the example, like this:

#include <SPI.h>
#include <SdFat.h>    // https://github.com/greiman/SdFat

SdFat SD;
File LogFile;

ArduinoOutStream coutF(LogFile);
ArduinoOutStream coutS(Serial);

void setup() 
{
  Serial.begin(9600);
  coutS << "hello";
  
  SD.begin(8);
  LogFile = SD.open("LOGFILE.TXT", FILE_WRITE);
  coutF << "howdy";
  LogFile.close();
}

void loop() {}

This writes "hello" to the serial monitor, and "howdy" to an SD file named LOGFILE.TXT.

Am I doing this right? I'm nervous because I don't feel like I quite know what I'm doing (because I can't understand the documentation).

I'm going through this exercise because I want to be able to rename files on the SD card, which the default SD library won't let you do. SdFat is apparently not quite a drop-in replacement for SD if your sketch uses Streaming.h. Are there other things I need to look out for?

I went ahead and tried to replace SD.h plus Streaming.h with SdFat.h in my sketch, and it required one change in addition to defining the streaming objects.

My old code for SD.h + Streaming.h:

#include <SPI.h>
#include <SD.h>
#include <Streaming.h>

File logFile;

void setup() 
{
  SD.begin(8);
  logFile = SD.open("LOGFILE.TXT", FILE_WRITE);
  logFile << "SD + Streaming";
  logFile.close();
}

void loop() {}

If I try to do this:

#include <SPI.h>
// #include <SD.h>
#include <SdFat.h>
#include <Streaming.h>

SdFat SD;
File logFile;

void setup() 
{
  SD.begin(8);
  logFile = SD.open("LOGFILE.TXT", FILE_WRITE);
  logFile << "SD + Streaming";
  logFile.close();
}

void loop() {}

...I get this error message from the compiler:

In file included from SD-plus-streaming.ino:4:0:
C:\Users\dweathers\Documents\Arduino\libraries\Streaming/Streaming.h:100:21: error: 'endl' redeclared as different kind of symbol
 enum _EndLineCode { endl };
                     ^
In file included from C:\Users\dweathers\Documents\Arduino\libraries\SdFat/utility/bufstream.h:27:0,
                 from C:\Users\dweathers\Documents\Arduino\libraries\SdFat/utility/ArduinoStream.h:29,
                 from C:\Users\dweathers\Documents\Arduino\libraries\SdFat/utility/FatLib.h:23,
                 from C:\Users\dweathers\Documents\Arduino\libraries\SdFat/SdFat.h:27,
                 from SD-plus-streaming.ino:3:
C:\Users\dweathers\Documents\Arduino\libraries\SdFat/utility/iostream.h:40:17: error: previous declaration of 'ostream& endl(ostream&)'
 inline ostream& endl(ostream& os) {
                 ^
Error compiling.

...which is kind of weird because I haven't even tried to use the "endl" object.

Here's how I got streaming to work with SdFat by itself:

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

SdFat SD;
File logFile;

ArduinoOutStream logStream(logFile);

void setup() 
{
  SD.begin(8);
  logFile = SD.open("LOGFILE.TXT", FILE_WRITE);
  logStream << "SdFat only";
  logFile.close();
}

void loop() {}

It looks like I need to keep two objects around with SdFat's streaming code, compared to SD+Streaming (which can use the SD file object both for file operations like open and close as well as streaming with the << operator).

IMO, I find this a bit clunky and confusing. It makes more sense to me to do it the way SD + Streaming does it.

And perhaps the author of SdFat also wanted it to work this way, and I have exposed a bug. If so, it might help to know I'm using Windows 7 Pro SP1, with Arduino 1.6.4.

Any feedback on this would be welcome. Thanks in advance.

ArduinoOutStream was only meant to be used with Serial and other non-file objects.

For file objects, use ifstream for input, ofstream for output or fstream for read/write.

These classes correspond to the standard C++ classes.

Here is a simple example with ifstream and ofstream.

Here is another example.

Few Arduino users have been interested in iostreams so I have removed many original examples.

C++ iostreams have many more features than Streaming.h. See this example for use of format manipulators.

fat16lib:
ArduinoOutStream was only meant to be used with Serial and other non-file objects.

For file objects, use ifstream for input, ofstream for output or fstream for read/write.

These classes correspond to the standard C++ classes.

Aha! That makes more sense than what I thought I was seeing. Thanks!

fat16lib:
Here is a simple example with ifstream and ofstream.

Here is another example.

Excellent, thanks. Examples help a lot.

fat16lib:
Few Arduino users have been interested in iostreams so I have removed many original examples.

Hmm, I wonder why? Too large of a footprint? Too complicated? What's the catch?

fat16lib:
C++ iostreams have many more features than Streaming.h. See this example for use of format manipulators.

OMG. For my part, I'm gonna learn how iostreams work right away. This makes formatted output downright easy.

fat16lib:
Few Arduino users have been interested in iostreams so I have removed many original examples.

I see your SdFat library has directory functions like mkdir, chdir, rmdir. And there's other directory type functions like delete files (sd.remove), list directory (sd.ls).

Maybe I missed it, but any reason why there are no library file copy functions (sd1.copy to destination sd2 or by wire/wireless using FTP)?

Maybe I missed it, but any reason why there are no library file copy functions (sd1.copy to destination sd2 or by wire/wireless using FTP)?

Copy doesn't fit very well as a member function of some SdFat class. It's more like an application. On a PC with Linux, OS X, or Windows, copy is an application, not part of the file system.

Also copy is very simple to implement as part of an application

  uint8_t buf[BUF_SIZE];
  int n;
  while ((n = file1.read(buf, sizeof(buf)) > 0) {
    file2.write(buf, n);
  }

Also many of you examples would require another library to be included in SdFat which won't really work.

I am just starting to play with SdFat - it is a great piece of work BTW. My project is a simple GPS datalogger which I plan to expand with GPRS tracking.

One thing i would like to do, whilst I'm still learning both the GPS and SdFat code, is write data to the SD card and for debug purposes also to the serial port. What I had hoped is something like this simplified idea

ArduinoOutStream coutS(Serial); // Serial print stream
ArduinoOutStream coutF(file);  //SD File Stream
...
...

if debug
   writeData(coutS)
else
  writeData(coutF);
...
...

void writeData(stream s) {
s << some formatted data
}

But reading this I understand I would be better using ioStream for the SD file stream - would that preclude me doing something like the above?

BTW You can probably guess I'm very much a C/C++ novice!