[primer]Chapter 8 The IO Library

1. 对c++流的概念根本没有灵活运用!!!没有深入认识。标准流读入的时候会忽略空白符(空格;换行符;制表符等)

2. IO库是一个面向对象的标准库。采用面向对象的继承关系使流操作对不同的设备(控制台窗口;磁盘文件;内存中的字符串)不同的字符都可以采用共同的操作

primer8

因为 IO 类型通过继承关联,所以可以只编写一个函数,而将它应用到三种类型的流上:控制台、磁盘文件或者字符串流(string streams)。sstream与fstream是最低层啊

标准库还定义了一组相关的类型,支持 wchar_t 类型。每个类都加上“w”前缀,以此与 char 类型的版本区分开来

对wiostream和iostream的理解:

istream in;in.open(…)不是说参数只能用char*型的,这个函数重载了六个,也支持wchar*!

文件路径有汉字时该路径需要用wstring;但是内存中即程序中读取写入汉字时直接使用string类型就行(多字节方式编码)。vs平台显示汉字编码的问题,如果要显示直接使用_T宏初始化的wstring,需要setlocale(LC_ALL, "chs");

	SetChsLocale();
	wstring path(_T("E://工作//test.txt"));
	wcout<<path<<endl;
	//不设置setchs时,只显示E:/,但是内存中path是没错的,可以用他打开指定文件
	ifstream in;
	in.open(path.c_str());
	string c;
	in>>c;
	cout<<c<<endl;

这里其实是字符编码的问题,具体看我转载的blog:

两种表示大型字符集的方法:宽字符(wide character,该字符集内每个字符使用相同的位长)以及多字节字符(multibyte character,每个字符可以是一到多个字节不等,而某个字节序列的字符值由字符串或流(stream)所在的环境背景决定(vs中位utf-8)。宽字符有不同的实现方式,vs中使用了unicode字符集编码方式

类似:printf, wprintf等输出到控制台或者文件的库函数只支持ANSI编码或多字节编码输出。其实这是符合C语言规范的,因为C标准并未支持Unicode,只是 很多C的实现将宽字符用unicode的位模式表示吧了(vs在选用unicode字符集时,wstring是将宽字符使用unicode表示)。这时我们需要通过setlocale函数来设置如何将unicode编码的宽字符转换成一种可以 输出的编码。c++的IO也不支持Unicode!

即STL不支持unicode,这个问题用最笨的方法吧,涉及到IO wstring时,将其转换成string!不是这样的!!!使用对流io.imbue(locale(“chs”));可以解决上述问题,不要使用setlocale()了,改成习惯用imbue。对读取unicode,则使用二进制io,记住读取的时候,io.seekg(2,ios::beg);跳过前两个字节;写入的时候,io.write(“/xff/xfe”,2);先写入标志字节

 

IO 对象不可复制或赋值:其原因在学习类和继承时阐明

不可复制有两个地方:1.只有支持复制的元素类型可以存储在 vector 或其他容器类型里。由于流对象不能复制,因此不能存储在 vector(或其他)容器中(即不存在存储流对象的 vector 或其他容器)。

2.第二个含义是:形参或返回类型也不能为流类型。如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用(非const的,因为用IO流读写会改名IO对象的状态)

    ofstream &print(ofstream&);              // ok: takes a reference, no copy
    while (print(out2)) { /* ... */ } // ok: pass reference to out2
8.2 条件状态
1.条件状态位

badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit 的问题通常是可以修正的。eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit

在使用流时,最好是用assert()设置一下中断来避免错误。因为如果你不检查条件状态时只是流操作失败并不报错

8.3

8.4. 文件流:

1、文件模式是文件的属性而不是流的属性,所以每次打开文件流时,之前的文件模式不会再保持的

2、二进制文件的读写
①put()
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。

②get()
get()函数比较灵活,有3种常用的重载形式:

一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。

另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。

还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='/n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'/n'。例如:

file2.get(str1,127,'A'); //从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。

③读写数据块
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:

read(char *buf,int num);
write(const char *buf,int num);

read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 char *,有时可能需要类型转换。

例:

char str1[]="I Love You";
int n[5];
ifstream in("xxx.xxx");
ofstream out("yyy.yyy");
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
in.read((char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
in.close();out.close();

四、检测EOF
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();

例: if(in.eof()) ShowMessage("已经到达文件尾!");

五、文件定位
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:

istream &seekg(streamoff offset,seek_dir origin);
ostream &seekp(streamoff offset,seek_dir origin);

streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:

ios::beg: 文件开头
ios::cur: 文件当前位置
ios::end: 文件结尾

这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:

file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节
file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节

     tellg()函数是返回当前读指针所在的位置。

tellp()函数是返回当前写指针所在的位置。

指定文件流指针的当前位置,返回的是文件指针到文件开始之间的数据长度, 结合seekg可以获得文件的的长度,例如file1.seekg(0,ios::end);

int a = in.tellg();即a就是文件的最大长度,同样也可以确定文件中某一处到末尾的长度。

注意: 在文件指针读取当前字节的时候文件指针会自动下移, 所以判断数据长度的位置的时候需要+1

设置seekg()以后,需要调用clear()函数清除上一次的设置,才能使下一次新的seekg()设置生效!!

8.5 字符串流要与一个string对象关联

sstream 类型除了继承的操作外,还各自定义了一个有 string 形参的构造函数,这个构造函数将 string 类型的实参复制给 stringstream 对象。对 stringstream 的读写操作实际上读写的就是该对象中的 string 对象。这些类还定义了名为 str 的成员,用来读取或设置 stringstream 对象所操纵的 string 值。

使用的一个例子就是split_string

	__inline void split_string(std::vector<std::string>& result, const std::string& input)
	{
	   std::stringstream steam(input);
	   std::string temp;
	   while (steam>>temp)//输入到新的temp对象
	   {
		   result.push_back(temp);
	   }
	}

另外一个重要用途是:stringstream 提供的转换和/或格式化

stringstream 对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。例如,有一个数值型数据集合,要获取它们的 string 表示形式,或反之。sstream 输入和输出操作可自动地把算术类型转化为相应的 string 表示形式,反过来也可以

    int val1 = 512, val2 = 1024;
    ostringstream format_message;
    // ok: converts values to a string representation
    format_message << "val1: " << val1 << "/n"//输出时则更改format_message关联的string对象
                   << "val2: " << val2 << "/n";
   // str member obtains the string associated with a stringstream
   istringstream input_istring(format_message.str());
   string dump; // place to dump the labels from the formatted message
   // extracts the stored ascii values, converting back to arithmetic types
   input_istring >> dump >> val1 >> dump >> val2;
   cout << val1 << " " << val2 << endl;

这里创建了一个名为 format_messageostringstream 类型空对象,并将指定的内容插入该对象。重点在于 int 型值自动转换为等价的可打印的字符串。相反,用 istringstreamstring 对象,即可重新将数值型数据找回来。读取 istringstream 对象自动地将数值型数据的字符表示方式转换为相应的算术值

这里对sstream的输出输入的理解:<<为输出,是将内容“输出到string对象”即插入到关联的string对象;而>>为输入,即由字符串流输入到一个新的string对象

		//string 与算术类型的转换!
		//int num=10;string a;
		//a=Cast_<string,int>(num)
		template <class target, class source> 
		target Cast_(const source& s_) 
		{ 
			stringstream ss;  //定义一个stringstream流 
			ss << s_;  //读入source 将source类型自动的转换成字符串
			target result; //返回值 
			ss >> result;  // 将字符串值自动转为相应的算术类型
			return result; // 
		} 

附录A中再谈IO库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值