初探ifstream与回车换行及类型匹配等几个问题

来源:http://blog.csdn.net/shellching/archive/2009/08/12/4438099.aspx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#include <iostream>
#include<fstream>
using namespace std;
 
/*本例:
    1、练习ifstream、ofstream读写文件基本方法;
    2、验证回车换行符号在文件读写中的状态和作用;
    3、验证几种判断文件末尾的方法;
    4、验证几种解决ifstream对读入类型不匹配数据的处理方法
 
回车与换行符:
    字符    名称                   ASCII值    控制字符
    '\n'    换行(New line)           010     LF (Line Feed)
    '\r'    回车(Carriage return)    013     CR (Carriage Return)
     
杨小进 0:31 2009-8-12
*/
 
//创建输入文件,为练习准备
void createFile(char *fname)
{
    ofstream ofs(fname);
    ofs << "aaaaa\n";
    ofs << "bbbbb\n";
    ofs << "11111\n";
    ofs << "22222\n";
    ofs.close();
}
 
//获取文件长度字节,会得到比输入更多的字节,因为 \n 被转换为 \r\n
int getFileLen(char *fname)
{
    ifstream ifs(fname);
    ifs.seekg(0, ios::end);     //移动文件指针到末尾
    int n = ifs.tellg();        //获取文件长度字节
    ifs.seekg(ios::beg);        //恢复指针到开始,对于接下来继续读有用
    ifs.close();
    return n;
}
 
//用read函数文本模式下读取文件,读到字节数小于真实文件大小,
//因为系统读 \r\n 时又转换为 \n, 只是\n被读进来了
//若是binary模式,则会读到实际文件大小的字节
void readFileRead(char *fname, ios_base::openmode om = ios_base::in)
{
    int n = getFileLen(fname);
    ifstream ifs(fname, om);
 
    char *pc = new char[n+1];
    memset(pc, 0, sizeof(char)*(n+1) );
    ifs.read(pc, n);
    if(om & ios_base::binary)
    {
        cout << " binary模式";
    }
    cout << " read()读取了"<< ifs.gcount() << "字节:\n";  
    cout << pc;
    delete pc;
    ifs.close();
}
 
//使用流提取符号读取文件,不管是何种模式,空白字符都会被 >> 略过
void readFileExtranction(char *fname)
{
    ifstream ifs(fname, ios_base::binary);
    char c;
    cout << "binary模式 >>读取:\n";
    while(!ifs.eof())
    {
        ifs >> c;            
        cout << c << "_";
    }
    ifs.close();
}
 
//使用Get在文本模式下读取文件内容,对于"\r\n"多跳过一个字符只读进'\n',指针移到'\n'后
//若在binary模式则是按照真实数据读取'\r','\n';
void readFileGet(char *fname, ios_base::openmode om = ios_base::in)
{
    ifstream ifs(fname, om);
    char c;
    if(om & ios_base::binary)
    {
        cout << " binary模式";
    }
    cout << " get()从第5字节开始读取3个字符:\n十进制:";
    ifs.seekg(4, ios::beg);        
    ifs.get(c);             //读取第5字节,为'a'
    cout << int(c) << "_"
    ifs.get(c);     //读取下一个字节应为13 = '\r',实际读进10 = '\n'
    cout << int(c) << "_"//若在binary模式下则是13 ='\r'
    ifs.get(c);     //读取下一个字节,为'b',若是binary则是10='\n'
    cout << int(c) << "_";
    ifs.close();
}
 
//使用Peek读取文件内容,文本模式下对于"\r\n"读进'\n';
//在binary模式下,对于"\r\n"则会读进'\r',peek始终都不会移动文件指针
void readFilePeek(char *fname, ios_base::openmode om = ios_base::in)
{
    ifstream ifs(fname, om);
    //ifstream ifs3("input.txt", ios_base::binary);
    char c;
    if(om & ios_base::binary)
    {
        cout << " binary模式";
    }
    cout << " peek()读取第6、7、8字节:\n";
    ifs.seekg(5, ios::beg);        
    c = ifs.peek();         //读取第6字节应为13 = '\r',实际上读进10 ='\n'
    cout << int(c) << "_";          //若在binary模式则是13 ='\r'
    ifs.seekg(6, ios::beg);        
    c = ifs.peek();         //读取第7字节,为10 ='\n'
    cout << int(c) << "_";
    ifs.seekg(7, ios::beg);        
    c = ifs.peek();         //读取第8字节,为'b'
    cout << int(c) << "_";
    ifs.close();
}
 
//通过eof()判断文件结束,若某行只有回车也算是一行,即使在文件尾部
void getOverEof(char *fname)
{
    ifstream ifs(fname);
    string str;
    int i = 0;
    cout << " eof()判断文件结束";
    while(!ifs.eof())                  
    {
        getline(ifs, str);             
        cout << "\n第" << ++i <<"行长度 " << str.length() << " : " << str;
    }
    ifs.close();
}
 
//通过good()判断文件结束,同eof,若某行只有回车也算是一行,即使在文件尾部
//因为使用了binary模式,所以getline比平时多读入一个字符'\r',忽略'\n'
void getOverGood(char *fname)
{
    ifstream ifs(fname, ios_base::binary);
    int i = 0;
    string str;
     
    cout << " binary模式 good()判断文件结束";
    while(ifs.good())
    {  
        getline(ifs, str);
        cout << "\n第" << ++i <<"行长度 " << str.length() << " : " << str;
        cout << " 第6字节" << int(str[5]);
    }
    ifs.close();
}
 
//通过getline()判断文件结束,只有回车且在文件末尾的空行不算一行
void getOverGetline(char *fname)
{
    ifstream ifs("input.txt");
    int i = 0;
    string str;
     
    cout << " getline()判断文件结束";
    while(getline(ifs, str))           
    {  
        cout << "\n第" << ++i <<"行长度 " << str.length() << " : " << str;
    }
    ifs.close();
}
 
//使用ifstream的提取符号从文本文件读入某种类型数据例如float或double时,
//若遇到字符串或其它非数字符号会发生错误,造成死循环,所以需要特别处理
bool readErr(char *fname)
{
    cout << "不匹配数据类型处理:";
    ifstream ifs(fname);     
     
    if( !ifs )                           
    {
        cout << "\n打开文件 " << fname << " 失败\n";
        return false;
    }
     
    int count=0;                                           
    int  dVal, sum=0;                                       
     
    while( !ifs.eof() )                              
    {
        ifs >> dVal;
         
        if(ifs.fail())  //错误判断,使用"!ifs"也可以,但是"ifs.bad()"不行
        {
            ifs.clear();    //清楚错误标志
            ifs.ignore(1);  //忽略当前非预期字符
            continue;   //继续读取下一个
        }
        else
        {
                cout << "\n第 " << ++count << "个数: " <<  dVal;
              sum += dVal;                                 
        }
    }
     
        ifs.close();           
     
        cout << "\n总共 " << count << " 个数,"
         << " 和为" << sum << endl;   
        return true;
}
 
int main()
{
    char fname[] = "input.txt";
    createFile(fname);
     
    cout << "文件长度:" << getFileLen(fname) << " 字节";
     
    cout << "\n-----------------------";
     
    readFileRead(fname);
     
    cout << "\n-----------------------";
     
    readFileRead(fname, ios_base::binary);
     
    cout << "\n-----------------------";
     
    readFileExtranction(fname);
     
    cout << "\n-----------------------";
     
    readFileGet(fname);
     
    cout << "\n-----------------------";
     
    readFileGet(fname, ios_base::binary);
     
    cout << "\n-----------------------";
     
    readFilePeek(fname);
     
    cout << "\n-----------------------";
     
    readFilePeek(fname, ios_base::binary);
     
    cout << "\n-----------------------";
     
    getOverEof(fname);
     
    cout << "\n-----------------------";
     
    getOverGood(fname);
     
    cout << "\n-----------------------";
     
    getOverGetline(fname);
     
    /*
    总结:windows系统中使用ofstream写文本文件时系统会把'\n'转换为'\n''\r'两个字符写入文件;
    若是单写入'\r'则不会做上述转换;通常读取时会相应把'\n''\r'两个字符转换为'\n';
    对于文本中单独的'\n'和'\r'读取时不会作特别转换,作为一个字符读出;
    使用流输入符号">>"读取字符时,无论使用何种模式打开文件,都会忽略空白字符\n\r等;
    使用get和peek读取时,若在文本模式下,对于文本中的"\r\n"只是作为一个字符'\n'对待;
    get和peek,若在二进制模式下,对于文本中的"\r\n"作为两个字符对待;
    getline在文本模式下忽略"\r\n",但是在binary模式下会忽略'\n',而不会忽略'\r';
    */
     
    cout << "\n-----------------------";
     
    readErr(fname);
     
    cout << endl;
    return 0;
}

posted on   大宝pku  阅读(3015)  评论(0编辑  收藏  举报

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架

导航

< 2010年4月 >
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示