When I use the std::ifstream to open a file that has been written in dos format, the ifstream does not seem to be able to open the file correctly since when I call good() on the stream afterwards it fails (returns false). I tried opening the file in binary mode as well as the default "in" mode and neither worked. If I convert the file to unix using dos2unix, everything works fine.
The goal behind being able to do this is that I want to be able to read a file and parse it, but I cannot guarantee that the file has not been saved in dos (Windows) or unix (Linux) format. Ideally, I would like to be able to use the ifstream.
Any suggestions?
Thanks!
The file format will NOT affect your ability to open it.
It is more likely that your path is not correct.
It seems extremely unlikely that GCC would do such a thing.
I suggest doing my_ifstream.exceptions( ios::failbit | ios::badbit ); before opening it, and running in the debugger. Then you can see where it ceased to be good.
Also, opening the file in binary mode (ios::in | ios::binary) should eliminate any possibility of the implementation being choosy over the contents of the file.
Related
Fstream does not create file if it is not there unless it is opened in an append mode. Append mode however forbids overwriting the original data, and I want to be able to seekp and seekg anywhere inside.
Unlike question asked here: std::fstream doesn't create file
I have a requirements for it not be in either append or truncate mods and still be able to to seekg and seekp anywhere in thise file.
It's a little more work, but you could attempt to open the fstream, and if it fails open (and close) an output file stream (ofstream) which creates the file, and then try to reopen the fstream.
This may properly belong to a different part of Stack Exchange but I don't think so - programmers.se is more about other things.
Getting to the question: There are things you can do with std::ios::binary that you cannot do in text mode (E.g. relative seek) but I cannot find anything to do in text mode that you cannot do in binary mode - even reading the file as text with e.g. std::getline()
So why would I ever open as text? As a perhaps-related question, why not open as binary by default? Whose use-case does that break?
EDIT Additional information
Here's what's causing me to ask:
I have a file which is created on a windows system - that is, the line-endings are CR LF.
I am opening it with std::ifstream using the std::ios::binary flag
I am parsing through the file with std::getline and getting exactly the behavior I would expect - getline reads one line at a time.
System: Windows 7 Pro
Compiler: g++ for MINGW32
What can you do in text mode that you can't do in binary? Read
text, for starters. A file opened in text mode automatically
translates between the '\n' character internally, and whatever
the system uses to delimit lines in files externally. It can
also recognize an arbitrary end of file, even when the
underlying system requires file sizes to be a multiple of some
fixed size.
The choice today is somewhat complicated by the fact that you
often have to access the files from incompatible systems. If
you have a file system mounted on both Windows and Unix, write
it as text under Windows, and read it as text under Unix, then
you'll see extra characters. In such cases, it may be
preferable to read and write binary, and to do the line end
handling yourself, according to whatever conventions you prefer.
Similarly, if the "file" is actually a socket, communicating
with another machine, you'll want to open it in binary, and
handle line endings yourself, according to the requirements of
the protocol.
Well stdin is opened by default in text mode, this allows the use of for example CTRL + Z to signal EOF so I don't see why you think there is no "need" to have streams opened in anyting except binary mode.
Is it possible in C++ to change the output mode of an open FILE* without closing and reopening it?
I have a FILE* opened in mode std::ios_base::out and would like to switch to std::ios_base::app in a more elegant way.
If you want to write at the end of the file, simply seek to the end of the file, it's the easier solution.
On POSIX system (including linux, unix, ...) and most likely on Windows too, it is not possible to change the open mode of a file once it has been openned. Thus you have to close it and reopen it.
If your operating system has some particularities which permit this and you don't care about portability, you can achieve this by using the right system call in a std::filebuf subclass, then creating your own std::fstream subclass.
I'm having a strange issue that I think I have a workaround for, but I'm trying to do a root cause analysis on.
I've been developing an application that runs on an embedded version of Ubuntu 10.04 LTS. When the application starts up, it reads in a config file off of an SD card, initializes a few classes, starts a logger which writes to the SD card, and then proceeds with it's operation. During development, it has been running fine when I start it manually through an SSH terminal.
I've recently been experimenting with having the application start automatically when the OS starts up. I have a script in init.d which does just that. However, I noticed that no log files are being generated now. I figured out it's not a problem with the SD card not being available because the config file gets read properly on startup, but an error is thrown when I attempt to open the log file for writing using fopen.
// Open the file
mLogFile = fopen(filename, "wb");
if(mLogFile == NULL)
{
printf("Error opening Log File [%d].\n", lnRetval);
return -1; //File couldn't be opened
}
I assumed it was just a permissions problem, but I can't understand why it doesn't work when I automatically start the software versus running it manually in a terminal. Furthermore, I can't understand why the config file gets read in properly but this file can't be opened.
The only difference I could see was that the config file reading is done using fstreams, while the logger is using C file I/O. So I experimented by placing the following code directly before the fopen call above (/home/root/etc is where the SD card is mounted).
std::ofstream out("/home/root/etc/log/testlog.log");
out << "I can write using fstreams.\n";
out.close();
That worked and generated the file when started through init.d. Now I'm completely stumped. Why does ofstream work and not fopen? Is there something fundamentally I'm missing?
Thanks in advance.
Your question does not provide enough information to answer, but the general approach to problems like this should be to run the program (in both forms) under strace and compare the sequence of syscalls made. That should quickly reveal what's happening differently. I suspect you'll just find the contents of filename are invalid...
As all we know in windows EOL is CRLF and in linux LF and CR in Mac. (more_info)
I want to write a program which reads as linux and Mac as well Win files line by line in Windows. To open file I would use fopen in "rt" mode, but I don't know how read lines. fgets reads until CRLF and LF under Windows but I want it to work for EOL=CR files also.
So what is the solution? Thanks in advance.
To open in "t" mode, the file must conform to the platform you are running on. Otherwise you just have to open in binary mode, and sort the difference out yourself.
The C library helps you write a program that works roughly the same on different platforms, but does not support "cross reading" the files.
As long as you open the file in rt mode (read - text), you should be fine. fgets() will return one line, and will handle the subtle differences between platforms. When writing to a file, use '\n' as the EOL, and you will get the correct line endings for your platform. This is the reason for opening the file in text mode. If you use binary mode, you will have to handle all the different line endings in your software.
So I couldn't find nothing good for me and decided to write my own my_fgets function which uses fgetc in body.