I have a bunch of legacy code that uses C-style file I/O (using FILE* streams, fprintf, fscanf, etc.) that I'd like to update to operate off of other data sources (e.g., downloading from or posting to the web, or to or from a custom data transfer cable).
If it used iostreams, this would be an easy update, but it doesn't.
Are there any C or C++ libraries for I/O that support different kinds of streams but that are source-compatible or mostly source-compatible with C's FILE* stream functions?
If source compatibility is too much to ask, I'd settle for "able to be search-and-replaced with a Perl script." fprintf and fscanf seem to be the major obstacles here; I haven't found any iostream-compatible versions of these.
I'm looking for a solution that will work in both Windows and Linux.
Example
As a trivial example, I have code like the following:
FILE *input = fopen(filename, "rt");
fscanf(input, "%d,%d,%d,%f", &f_id, &f_units, &h_index, &h_default);
fclose(input);
I'd like to update it to handle data that's of the same format but may come from other sources, without having to worry about the intricacies of how exactly to replicate fscanf's semantics myself (since I have many, many fscanf and fprintf calls that would need updating). Something like this would work, except that I've been unable to find anything like istream_scanf:
std::istream *input = make_http_istream(url);
istream_scanf(*input, &f_id, &f_units, &h_index, &h_default);
delete input;
Related
Suppose you declare an instance of std::ifstream or std::ofstream but is_open() returns 0
Example:
std::ifstream file("myfile.txt");
if (!file.is_open()) {
printf("Could not open file\n");
return;
}
Since the file never opened, do I still need to call file.close() after the printf statement?
No, you can only close an open file (similar to how you cannot close an already closed door - there is nothing to be done).
Extra note: Please do not combine the C I/O library (Xprintf family of functions) with the C++ I/O library (iostreams).
Consider using code like this:
std::ifstream file("myfile.txt");
if (!file.is_open()) {
std::cerr << "Could not open file\n";
return;
}
Edit (reasons not to use C IO API and C++ IO API together):
Using both APIs imposes synchronization between them, with priority towards the C API (i.e. the C api remains as fast, but IO streams will become slower, due to synchronization requirements).
It is inconsistent, using two very different concepts/abstraction levels for the same task. In more complex code, you will have to write twice the error handling (they impose different styles of error handling in client code), have both their limitations and combine their bad aspects (C API is prone to buffer overflows/security issues on reading and fails silently, unless you pay lots of attention to writing/maintenance of each API call, C++ API calls can be verbose).
They do not need to be particularly close (or far) appart, it is simply a bad programming practice.
This is similar to using a generic ODBC C API for reading table1 of your database, and ActiveX Data Objects for reading table2 in the same database, and the same program, or using Qt for your development, then hacking over it with raw WinAPI calls: you have twice the problems to solve (and many times end up implementing the solution to the same problems twice).
Is it possible to convert an istream like std::cin to a FILE *? A cross-platform solution would be a plus.
EX: (FILE *)std::cin.
No, there is no standard way to obtain a FILE* from an IOStreams stream, nor vice versa.
std::cin is usually bound to file descriptor 1 (or in FILE * form, stdin).
You could just use that. Other than that, the only way to do so is either determine the file descriptor (unlikely) or the filename and use fopen to get a FP
There is no easy way using FILE* I would advise you to use fstream instead.
std::ifstream in("in.txt");
std::cin.rdbuf(in.rdbuf());
This way your redirect cin to your input file stream.
Though it is possible that your IOStreams implementation may be implemented using a FILE*, the standard does not provide any way of you accessing this information. However, it is of my knowledge that libstdc++ has a non-standard extension __gnu_cxx::stdio_filebuf, which is a wrapper around a FILE*. You can use its file() method to return a pointer to the file.
Note that this class is non-portable and non-standard. I think you're better off writing your own stream buffer that emulates its behavior.
If you have a GNU userland (just about guaranteed on Linux), take a look at fopencookie(). That allows you to adapt any source / sink to a FILE*.
The linked man-page contains in-depth guidance on how to write the adaptor.
I'm using a third-party library that allows conversion between two file formats A and B. I would like to use this library to load a file of format A and convert it to format B, but I only need the converted representation in memory. So I would like to do the conversion without actually saving a file of the target format to disk and rather obtain an unsigned char* buffer or something similar. Unfortunately the libraries only conversion function is of the form
void saveAsB(A& a, std::FILE *const file);
What can I do? Is there any way to redirect the write operations performed on the handle to some buffer?
If your platform supports it, use open_memstream(3). This will be available on Linux and BSD systems, and it's probably better than fmemopen() for your use case because open_memstream() allocates the output buffer dynamically rather than you having to know the maximum size in advance.
If your platform doesn't have those functions, you can always use a "RAM disk" approach, which again on Linux would be writing a "file" to /dev/shm/ which will never actually reach any disk, but rather be stored in memory.
Edit: OK, so you say you're using Windows. Here's an outline of what you can try:
Open a non-persisted memory-mapped files.
Use _open_osfhandle to convert the HANDLE to an int file descriptor.
Use _fdopen to convert the int file descriptor to FILE*.
Cross your fingers. I haven't tested any of this.
I found this reference useful in putting the pieces together: http://www.codeproject.com/Articles/1044/A-Handy-Guide-To-Handling-Handles
Edit 2: It looks like CreateFileMapping() and _open_osfhandle() may be incompatible with each other--you would be at least the third person to try it:
https://groups.google.com/forum/#!topic/comp.os.ms-windows.programmer.win32/NTGL3h7L1LY
http://www.progtown.com/topic178214-createfilemapping-and-file.html
So, you can try what the last link suggested, which is to use setvbuf() to "trick" the data into flowing to a buffer you control, but even that has potential problems, e.g. it won't work if the library seeks within the FILE*.
So, perhaps you can just write to a file on some temporary/scratch filesystem and be done with it? Or use a platform other than Windows? Or use some "RAM disk" software.
If you can rely on POSIX being available, then use fmemopen().
Is there a way I can check if an istream of ostream is seekable?
I suspect doing a test seek and checking for failbit is not correct
since the seek can fail for unrelated reasons.
I need this to work on Linux and mac, if that makes a difference.
Iostreams doesn't give you much. Stream objects are just wrappers around a buffer object derived from class std::streambuf. (Assuming "narrow" characters.) The standard derived buffer classes are std::stringbuf for strings and std::filebuf for files. Supposing you're only interested in files, std::filebuf is just a simple wrapper around the C library functionality. The C library does not define a way to determine if a FILE object supports seeking or not, besides attempting to do so, so neither does C++.
For what it's worth, the semantics of seek vary a bit. Some platforms might allow you to "seek" a pipe but only to the current position, to determine how many characters have been read or written. Seeking past the end might resize the file, or might cause the next write operation to resize the file, or something in between.
You might also try checking errno if badbit is set (or, as I prefer, use exceptions instead of flags).
fopen_s <--> OpenFile
fclose <--> CloseFile
Is my assumption correct?
I wonder what is better to use, OpenFile or CreateFile. The latter gives more freedom, but is it faster?
I would use neither in Delphi – I would use streams. Low level file handling is messy and error-prone, it's much better to use higher level routines if you can.
You ask which is faster, OpenFile or CreateFile. They are basically the same, but any method of opening a file is going to map onto the system call anyway so the performance will be the same no matter how you do it. What's more, when does performance for opening a file matter, it's when reading or writing that time is expended.
Any questions about performance are hard to answer without context. The answer for an app which reads thousands of small text files is different from one which streams backups to a tape drive, for example.
Anyway, to stress my original point, take advantage of the excellent high-level framework that Delphi provides, use streams, avoid low-level I/O and enjoy!
So, how does one use a Delphi stream? I'll try to illustrate this with a made up example of writing some text, in a string, to a file.
procedure SaveTextToFile(FileName, Text: string);
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
Try
if Length(Text)>0 then
Stream.WriteBuffer(Text[1], Length(Text)*SizeOf(Char));
Finally
Stream.Free;
End;
end;
It's pretty self-explanatory. The second parameter to the TFileStream constructor determines the file mode. Here we want to create a brand new file and so if any contents exist, they are removed. You can also specify file sharing with this parameter.
The code to write the buffer out has a little boiler-plate but again is very simple.
Loading it back results in an almost identical routine:
function LoadTextFromFile(FileName: string): string;
var
Stream: TFileStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead);
Try
SetLength(Result, Stream.Size div SizeOf(Char));
if Length(Result)>0 then
Stream.ReadBuffer(Result[1], Length(Result)*SizeOf(Char));
Finally
Stream.Free;
End;
end;
If you wish to seek around the file then you can set the Position property of the stream, or call the Seek() method. The advantage of the latter is that you can seek from current position or end position.
Streams are idiomatic Delphi. They are used pervasively in the RTL and VCL and by 3rd party libraries. They signal errors with exceptions in the native Delphi manner. There are many different stream classes that all derive from a common ancestor and many routines accept this common ancestor.
Low-level Delphi file handling is done like this:
procedure Proc;
var
f: file; // or f: TextFile;
begin
FileMode := fmOpenRead; // or fmOpenWrite or fmOpenReadWrite
AssignFile(f, 'C:\file.txt');
try
// Reset/Rewrite
// A number of BlockRead/BlockWrite/ReadLn/WriteLn...
finally
CloseFile(f);
end;
end;
This is the classic way of working with files in Delphi, and this is what corresponds to the C++ functions.
OpenFile and CreateFile are not Delphi functions, so they cannot correspond to the C++ functions. Instead, these are functions of the Windows API, which is available in all (Windows) programming languages. The former, OpenFile, is not recommended. Use CreateFile instead. But if you use the Windows API file-handling functions to open/create a file, you should also use these to read/write the file, e.g. the ReadFile function, and you must finish by using the CloseHandle function.
Notice in particular that OpenFile is a function of the Windows API, whereas CloseFile is a Delphi RTL function, so you cannot even use these together! Delphi: AssignFile->CloseFile; Windows API: CreateFile->CloseHandle.
You should also know, that there are high-level functions for managing files in the Delphi RTL (run-time library). I am sure other users will promote these.
It's been a long while since I have done any Delphi programming, but I remember that file IO were much better served using TStream suite of classes (TFileStream for file IO). They are essentially the equivalent mechanism of C++'s IO streams library, which is, of course, the preferred way of doing file IO in C++. See this simple example and this wiki.