Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Mode

Meaning

For

Description

 

 

 

 

append

Output

Appends data at the end of the file.

app

 

 

 

binary

Input/Output Input and output is done in binary.

binary

 

 

 

input

Input

Opens the file for reading.

in

 

 

 

output

Output

Opens the file for writing.

out

 

 

truncate

Input/Output Removes contents of the file when opening.

trunc

 

 

at end

Input

Goes to the end of the file when opening.

ate

Note: Setting the binary mode lets the data be read/written exactly as-is; not setting it enables the translation of the newline '\n' character to/from a platform specific end of line sequence.

For example on Windows the end of line sequence is CRLF ("\r\n").

Write: "\n" => "\r\n"

Read: "\r\n" => "\n"

Section 12.5: Reading an ASCII file into a std::string

std::ifstream f("file.txt");

if (f)

{

std::stringstream buffer; buffer << f.rdbuf(); f.close();

// The content of "file.txt" is available in the string `buffer.str()`

}

The rdbuf() method returns a pointer to a streambuf that can be pushed into buffer via the stringstream::operator<< member function.

Another possibility (popularized in E ective STL by Scott Meyers) is:

std::ifstream f("file.txt");

if (f)

{

std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());

// Operations on `str`...

}

This is nice because requires little code (and allows reading a file directly into any STL container, not only strings) but can be slow for big files.

NOTE: the extra parentheses around the first argument to the string constructor are essential to prevent the most vexing parse problem.

Last but not least:

std::ifstream f("file.txt");

if (f)

{

f.seekg(0, std::ios::end);

GoalKicker.com – C++ Notes for Professionals

58

const auto size = f.tellg();

std::string str(size, ' '); f.seekg(0); f.read(&str[0], size); f.close();

// Operations on `str`...

}

which is probably the fastest option (among the three proposed).

Section 12.6: Writing files with non-standard locale settings

If you need to write a file using di erent locale settings to the default, you can use std::locale and std::basic_ios::imbue() to do that for a specific file stream:

Guidance for use:

You should always apply a local to a stream before opening the file.

Once the stream has been imbued you should not change the locale.

Reasons for Restrictions: Imbuing a file stream with a locale has undefined behavior if the current locale is not state independent or not pointing at the beginning of the file.

UTF-8 streams (and others) are not state independent. Also a file stream with a UTF-8 locale may try and read the BOM marker from the file when it is opened; so just opening the file may read characters from the file and it will not be at the beginning.

#include <iostream> #include <fstream> #include <locale>

int main()

{

std::cout << "User-preferred locale setting is "

<<std::locale("").name().c_str() << std::endl;

//Write a floating-point value using the user's preferred locale. std::ofstream ofs1;

ofs1.imbue(std::locale("")); ofs1.open("file1.txt");

ofs1 << 78123.456 << std::endl;

//Use a specific locale (names are system-dependent)

std::ofstream ofs2; ofs2.imbue(std::locale("en_US.UTF-8")); ofs2.open("file2.txt");

ofs2 << 78123.456 << std::endl;

// Switch to the classic "C" locale std::ofstream ofs3; ofs3.imbue(std::locale::classic()); ofs3.open("file3.txt");

ofs3 << 78123.456 << std::endl;

}

Explicitly switching to the classic "C" locale is useful if your program uses a di erent default locale and you want to

GoalKicker.com – C++ Notes for Professionals

59

ensure a fixed standard for reading and writing files. With a "C" preferred locale, the example writes

78,123.456

78,123.456

78123.456

If, for example, the preferred locale is German and hence uses a di erent number format, the example writes

78 123,456

78,123.456

78123.456

(note the decimal comma in the first line).

Section 12.7: Checking end of file inside a loop condition, bad practice?

eof returns true only after reading the end of file. It does NOT indicate that the next read will be the end of

stream.

while (!f.eof())

{

//Everything is OK f >> buffer;

//What if *only* now the eof / fail bit is set?

/* Use `buffer` */

}

You could correctly write:

while (!f.eof())

{

f >> buffer >> std::ws;

if (f.fail()) break;

/* Use `buffer` */

}

but

while (f >> buffer)

{

/* Use `buffer` */

}

is simpler and less error prone.

Further references:

std::ws: discards leading whitespace from an input stream

std::basic_ios::fail: returns true if an error has occurred on the associated stream

GoalKicker.com – C++ Notes for Professionals

60

Section 12.8: Flushing a stream

File streams are bu ered by default, as are many other types of streams. This means that writes to the stream may not cause the underlying file to change immediately. In oder to force all bu ered writes to take place immediately, you can flush the stream. You can do this either directly by invoking the flush() method or through the std::flush stream manipulator:

std::ofstream os("foo.txt");

os << "Hello World!" << std::flush;

char data[3] = "Foo"; os.write(data, 3); os.flush();

There is a stream manipulator std::endl that combines writing a newline with flushing the stream:

// Both following lines do the same thing os << "Hello World!\n" << std::flush;

os << "Hello world!" << std::endl;

Bu ering can improve the performance of writing to a stream. Therefore, applications that do a lot of writing should avoid flushing unnecessarily. Contrary, if I/O is done infrequently, applications should consider flushing frequently in order to avoid data getting stuck in the stream object.

Section 12.9: Reading a file into a container

In the example below we use std::string and operator>> to read items from the file.

std::ifstream file("file3.txt"); std::vector<std::string> v;

std::string s;

while(file >> s) // keep reading until we run out

{

v.push_back(s);

}

In the above example we are simply iterating through the file reading one "item" at a time using operator>>. This same a ect can be achieved using the std::istream_iterator which is an input iterator that reads one "item" at a time from the stream. Also most containers can be constructed using two iterators so we can simplify the above code to:

std::ifstream file("file3.txt");

std::vector<std::string> v(std::istream_iterator<std::string>{file}, std::istream_iterator<std::string>{});

We can extend this to read any object types we like by simply specifying the object we want to read as the template parameter to the std::istream_iterator. Thus we can simply extend the above to read lines (rather than words) like this:

//Unfortunately there is no built in type that reads line using >>

//So here we build a simple helper class to do it. That will convert

//back to a string when used in string context.

struct Line

GoalKicker.com – C++ Notes for Professionals

61