天天看点

深入输入输出流

深入输入输出流

一、相关日志

输入输出流(一)

http://blog.163.com/zhoumhan_0351/blog/static/39954227201002945157577/

输入输出流(二)

http://blog.163.com/zhoumhan_0351/blog/static/39954227201003005237697/

输入输出流(三)

http://blog.163.com/zhoumhan_0351/blog/static/39954227201003095620780/

C++ I/O流技术

http://blog.163.com/zhoumhan_0351/blog/static/3995422720103171303182/

C++流类库与C的I/O操作优势比较,文件与流

http://blog.163.com/zhoumhan_0351/blog/static/399542272010030103055465/

C++基础概念(基本语法)

http://blog.163.com/zhoumhan_0351/blog/static/39954227201002192139554/

二、深入输入输出流

1)C语言的printf遇到了问题:

The stumbling block is the runtime interpreter used for the variable argument list 

functions. This is the code that parses your format string at runtime and grabs and 

interprets arguments from the variable argument list. It’s a problem for four reasons.

(1)Even if you use only a fraction of the functionality of the interpreter, the whole 

thing gets loaded into your executable. 

(2)Because the interpretation happens at runtime, you can’t get rid of a performa- 

nce overhead.

(3)Because the format string is not evaluated until runtime, there can be no compile- 

time error checking.

(4)the most crucial problem is that the printf( ) family of functions is not particularly 

extensible. They’re really designed to handle only the basic data types in C (char, int, 

float, double, wchar_t, char*, wchar_t*, and void*) and their variations. and we also 

can not overhide printf and scanf overloaded functions must have different types in 

their argument lists, and the printf( ) family hides its type information in the format 

string and in the variable argument list. 

2、自己定义一个插入符和提取符

Defining inserters and extractors for your own classes is just a matter of overloading 

the associated operators to do the right things, namely:

· Make the first parameter a non-const reference to the stream (istream for input, 

ostream for output).

· Perform the operation by inserting/extracting data to/from the stream (by processing 

the components of the object).

· Return a reference to the stream.

ostream& operator<<(ostream& os, const Date& d) {

  os << setw(2) << d.getMonth() << '-'

     << setw(2) << d.getDay() << '-'

     << setw(4) << setfill(fillc) << d.getYear();

  return os;

}

get()遇到界定符时停止执行,但是不从输入流中提取界定符,而返回(此时指针指向界定符);而getline()遇到界定符时从流中提取界定符,但是不会把它存储到结果缓冲区中,此时指针指向界定符的下一个字符。

int get();&

istream& get( char* pch, int nCount, char delim = '\n' );

istream& get( unsigned char* puch, int nCount, char delim = '\n' );

istream& get( signed char* psch, int nCount, char delim = '\n' );

istream& get( char& rch );

istream& get( streambuf& rsb, char delim = '\n' );//把数据写入到对象rsb中。

3、处理流错误

Stream state

The ios_base class, from which ios derives, defines four flags that you can use to test 

the state of a stream:

我们通过流类的成员函数good()来检测流的读取存入状态,如果前三种都没有设置则返回true。The eof( ) function returns true if eofbit is set, which happens with an attempt to read 

from a stream that has no more data (usually a file).The fail( ) function returns true if 

either failbit or badbit is set, and bad( ) returns true only if the badbit is set.

    我们可以通过流成员函数clear来清除上述设置,同时可以进行新设置。

myStream.clear(); // Clears all error bits

myStream.clear(ios::failbit | ios::eofbit);

此外,setstate()用来设置标志位。

int i;

while(myStream >> i)

cout << i << endl;

      Remember that operator>>( ) returns its stream argument, so the while statement 

above tests the stream as a Boolean expression. This particular example assumes that 

the input stream myStream contains integers separated by white space. 

The function ios_base::operator void*( ) simply calls good( ) on its stream and 

returns the result. Because most stream operations return their stream, using this 

idiom is convenient.

        也就是说,流函数对象operator>>( ) 的返回值为 ios_base::operator void*( )函数调用good()而得的结果。它是一个bool型的值。当没有遇到物理上的致使错误,或没有遇到文件结束,或没遇到非法数据时,good()返回真。

The exceptions( ) stream member function takes a parameter representing the 

state bits for which you want exceptions to be thrown. Whenever the stream 

encounters such a state, it throws an exception of type std::ios_base::failure, which 

inherits from std::exception.

习惯上优先使用函数operator void*()而不是operator bool(),因为从bool型隐匿转换到int型会引起错误。函数operator void*()在布尔表达式中应当隐式调用。

you might want to enable exceptions only for the errors represented by badbit, 

which you would do like this:

myStream.exceptions(ios::badbit);

You enable exceptions on a stream-by-stream basis, since exceptions( ) is a member function for streams. The exceptions( )

 function returns a bitmask(of type 

iostate, which is some compiler-dependent type convertible to int) indicating which 

stream states will cause exceptions. If those states have already been set, an exception 

is thrown immediately. Of course, if you use exceptions in connection with streams, 

you had better be ready to catch them, which means that you need to wrap all stream 

processing with a try block that has an ios::failure handler. 

4、文件输入输出流

在使用read()或write(),或使用流指针定位命令的时候应当以二进制模式打开文件。

深入输入输出流

5、输入输出流缓冲

每个输入输出流对象包含一个指向streambuf的指针,来处理输入输出中的缓存功能。

深入输入输出流

To allow you to access the streambuf, every iostream object has a member function call

ed rdbuf( ) that returns the pointer to the object’s streambuf. This way you can call 

any member function for the underlying streambuf. 我们可以把这个函数与<<相连,就样就把右边对象中的字符输出到左边对象中去。

//: C04:Stype.cpp

// Type a file to standard output.

#include <fstream>

#include <iostream>

using namespace std;

int main() {

 ifstream in("C:\\bsmain_runtime.log");

  cout << in.rdbuf(); // Outputs entire file

} ///:~

++++++++++++++++++++++++++

我们用另一种方法:

//: C04:Sbufget.cpp

// Copies a file to standard output.

#include <fstream>

#include <iostream>

using namespace std;

int main() {

ifstream in("C:\\bsmain_runtime.log");

  streambuf& sb = *cout.rdbuf();

  while(!in.get(sb).eof()) {

    if(in.fail())          // Found blank line

      in.clear();

    cout << char(in.get()); // Process '\n'

  }

} ///:~

    流缓冲区不会被复制,因为它们没有拷贝函数。

6、在输入输出流中定位

1)绝对位置

streampos tellg();

A streampos type, corresponding to a long

tellp()//输出流

tellg()//输入流

2)相对位置

ostream& seekp( streampos pos );

ostream& seekp( streamoff off, ios::seek_dir dir );

istream& seekg( streampos pos );

istream& seekg( streamoff off, ios::seek_dir dir );

pos

The new position value; streampos is a typedef equivalent to long.

off

The new offset value; streamoff is a typedef equivalent to long.

dir

The seek direction. Must be one of the following enumerators: 

ios::beg   Seek from the beginning of the stream.

ios::cur   Seek from the current position in the stream.

ios::end   Seek from the end of the stream. 

    表示从dir位置开始偏移时的起始位置,如果off是正值,则指针加off,如果是负值,则指针减off。

7、字符串输入输出流

    直接对内存而不是文件和标准输出进行操作。当然,有时,我们把内存也看作是一种文件。

深入输入输出流

//: C04:Istring.cpp

// Input string streams.

#include <iostream>

#include <sstream>

#include <string>

using namespace std;

int main() {

  istringstream s("47 1.414 This is a test");//输入流

  int i;

  double f;

  s >> i >> f; // Whitespace-delimited input

  string buf2;

  cout<<i<<" "<<f<<" ";

  s >> buf2;

  cout<<buf2;

  cout << s.rdbuf(); // " is a test"

} ///:~

说明:对于从字符串流中提取数据时,我们应当注意到是依据于数据的类型进行摘录,不是以“以空格作为首选界定符的字符集”。如果f定义为int的话,那么其值为1,而非1.414,这样,下一个double型的变量将提取为0.414。

//: C04:Ostring.cpp {RunByHand}

// Illustrates ostringstream.

#include <iostream>

#include <sstream>

#include <string>

using namespace std;

int main() {

  cout << "type an int, a float and a string: ";

  int i;

  float f;

  cin >> i >> f;

  cin >> ws; // Throw away white space

  string stuff;

  getline(cin, stuff); // Get rest of the line

  ostringstream os;//输出流

  os << "integer = " << i << endl;

  os << "float = " << f << endl;

  os << "string = " << stuff << endl;

  string result = os.str();

  cout << result << endl;

} ///:~

说明:ostringstream流对象可以管理动态字符缓冲区,我们用成员函数str()将输出结果格式化为string对象。由于每次调用str()函数都会返回一个新的string对象,所以字符串流内置的stringbuf对象不会被破坏。

下面的一个例子将用输入输出流:

//: C04:StringSeeking.cpp {-bor}{-dmc}

// Reads and writes a string stream.

#include <sstream>

#include <string>

#include "iostream"

using namespace std;

int main() {

  string text = "We will hook no fish";

  stringstream ss(text);

  ss.seekp(0, ios::end);

  ss << " before its time.";

  // Change "hook" to "ship"

  cout<<ss.str()<<endl;

  ss.seekg(8, ios::beg);

  string word;

  ss >> word;//还以以空格结束符。

  cout<<word<<endl;

  ss.seekp(8, ios::beg);

  ss <<"ship";//覆盖

  // Change "fish" to "code"

  cout<<ss.str()<<endl;

  ss.seekg(16, ios::beg);

  ss >> word;

  cout<<word<<endl;

  cout<<ss.str()<<endl;

  ss.seekp(16, ios::beg);

  ss <<"code";

  cout<<ss.str()<<endl;

  ss.str("A horse of a different color.");

  cout<<ss.str()<<endl;

} ///:~

深入输入输出流

说明: ss <<"ship";//执行时是覆盖原值,在相应地址处放入新值,而不是插入,

    字符串流比文件流更好使用,任何时候都可以从流的读状态切换到写状态,或者反之。

继续阅读