tags:

views:

339

answers:

6

Hi, I am writing a file splitting program, to assist with using large files with iPod notes. I want to use tmpfile() in cstdio but it returns a file* not an fstream object. I know it's not possible in standard C++ but does anyone know any libraries that work well with the standard that have the ability to convert a FILE* to an std::fstream object? Or, if not is tmpfile() functionality available in the standard, or another library?

Thanks!

My OS is Windows XP and I use either Dev-C++ 4.9.9.2 or MS Visual Studio 2008 as my compiler.

A: 

You could use tmpnam mktmp to obtain a temporary file name, open it with a stream and then delete it with remove.

char *name;
ifstream stream;

name = mktmp("filename");
stream.open(name);
//do stuff with stream here.

remove(name);//delete file.
Tom
This is not considered to be a secure practice, since someone could theoretically inject a file with the selected name into the temp directory before you have a chance to open it. The man page for tmpnam(3) specifically says "Never use this function. Use mkstemp(3) or tmpfile(3) instead."
Tyler McHenry
@Tyler McHenry Thanks, editing.
Tom
mktemp is just as bad as tmpnam -- as @Tyler says, you need mkstemp or tmpfile. There is no secure way to obtain a "temp name" for a "temporary file that's not really temporary (doesn't disappear when closed)".
Alex Martelli
A: 

Even if you manage to convert a FILE* to an std::fstream, that won't work as advertised. The FILE object returned by tmpfile() has a special property that, when close()'d (or when the program terminates), the file is automatically removed from the filesystem. I don't know how to replicate the same behavior with std::fstream.

Juliano
A: 

Instead of using std::fstream, you could write a simple wrapper class around FILE*, which closes it on destruction. Should be quite easy. Define operators like << as necessary. Be sure to disallow copying, to avoid multiple close() calls.

Alex
A: 

You can use the benefits of c++ streams by pumping your data via the << syntax into a std::stringstream and later write it the .str().c_str() you get from it via the the C-API to the FILE*.

#include <sstream>
#include <cstdio>
#include <string>

using namespace std;

int main()
{
  stringstream ss;
  ss << "log start" << endl;

  // ... more logging

  FILE* f_log = fopen("bar.log", "w");
  string logStr =  ss.str();
  fwrite(logStr.c_str(), sizeof(char), logStr.size(), f_log); 
  fclose(f_log);

  return 0;
}
Maik Beckmann
+2  A: 

If all you want is a temporary file, use tmpnam() instead. That returns char* name that can be used for a temporary file, so just open a fstream object with that name.

Something like:

#include <cstdio>
#include <fstream>

...
char name[L_tmpnam];
tmpnam(name);

//also could be:
//char *name;
//name = tmpnam(NULL);

std::fstream file(name);

You do have to delete the file yourself, though, using remove() or some other method.

DeadHead
A: 

g++ has __gnu_cxx::stdio_filebuf and __gnu_cxx::stdio_sync_filebuf, in ext/stdio_filebuf.h and ext/stdio_sync_filebuf.h. It should be straight-forward to extract them from libstdc++ if your compiler is not g++.

Martin v. Löwis