C++文件的读取写入

 在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:

1、插入器(<<)
  向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<''\n'';就表示把字符串"Write Stdout"和换行字符(''\n'')输出到标准输出流。

2、析取器(>>)
  从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。

  在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。

一、打开文件
  在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:

void open(const char* filename,int mode,int access);

参数:

filename:  要打开的文件名 
mode:    要打开文件的方式 
access:   打开文件的属性
打开文件的方式在类iOS(是所有流式I/O类的基类)中定义,常用的值如下:

ios::app:   以追加的方式打开文件 
ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性 
ios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文 
ios::in:    文件以输入方式打开 
ios::out:   文件以输出方式打开 
ios::nocreate: 不建立文件,所以文件不存在时打开失败  
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败 
ios::trunc:  如果文件存在,把文件长度设为0 
  可以用“或”把以上属性连接起来,如ios::out|ios::binary

  打开文件的属性取值是:

0:普通文件,打开访问 
1:只读文件 
2:隐含文件 
4:系统文件 
  可以用“或”或者“+”把以上属性连接起来 ,如3或1|2就是以只读和隐含属性打开文件。

  例如:以二进制输入方式打开文件c:\config.sys

  fstream file1;
  file1.open("c:\\config.sys",ios::binary|ios::in,0);

  如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:

  file1.open("c:\\config.sys");<=>file1.open("c:\\config.sys",ios::in|ios::out,0);

  另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:

  fstream file1("c:\\config.sys");

  特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。

  ifstream file2("c:\\pdos.def");//以输入方式打开文件
  ofstream file3("c:\\x.123");//以输出方式打开文件

  所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。

二、关闭文件
  打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。

三、读写文件
  读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式

  1、文本文件的读写
  文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:

  file2<<"I Love You";//向文件写入字符串"I Love You"
  int I;
  file1>>I;//从文件输入一个整数值。

  这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些

操纵符 功能 输入/输出 
dec 格式化为十进制数值数据 输入和输出 
endl 输出一个换行符并刷新此流 输出 
ends 输出一个空字符 输出 
hex 格式化为十六进制数值数据 输入和输出 
oct 格式化为八进制数值数据 输入和输出 
setpxecision(int p) 设置浮点数的精度位数 输出

  比如要把123当作十六进制输出:file1<<hex<<123;要把3.1415926以5位精度输出:file1<<setpxecision(5)<<3.1415926。

  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(unsigned char *buf,int num);
    write(const unsigned char *buf,int num);

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

例:

    unsigned 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((unsigned 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);
% o" f2 R# S4 o% h8 O& Q+ m2 ]//把文件的读指针从当前位置向后移1234个字节

   file2.seekp(1234,ios::beg);) \. J* G+ p! P9 V
//把文件的写指针从文件开头向后移1234个字节

fstream的用法


: V. q$ d) `8 H: m. t3 F8 B3 [

开一个文件

fstream f;

f.open("1.txt", ios::in | ios::binary);

if (!f.is_open()) // 检查文件是否成功打开


5 @7 V/ d/ g0 F& Icout << "cannot open file." << endl;

ios::inios::bianry均为int定义文件打开的方式。

ios::in
& o% W' c/ g5 h1 A0 m-- 打开文件用于读。

ios::out -- 打开文件用于写,如果文件不存在,则新建一个;存在则清空其内容。

ios::binary -- 以二进制bit流方式进行读写,默认是ios::text,但最好指定这种读写方式,即使要读写的是文本。因为在ios::text模式下,在写入时'\ n'字符将转换成两个字符:回车+换行(HEX: 0D 0A) 写入,读入时作逆转换,这容易引起不必要的麻烦。

ios::app -- 打开文件在文件尾进行写入,即使使用了seekp改变了写入位置,仍将在文件尾写入。

ios::ate -- 打开文件在文件尾进行写入,但seekp有效。

读写位置的改变

f.seekg(0, ios::beg); // 改变读入位置 g mean Get

f.seekp(0, ios::end); // 改变写入位置 p mean Put

第一个参数是偏移量offset(long),第二个参数是offset相对的位置,三个值:

ios::beg -- 文件头
" Q" ]: |5 Z/ @' i/ k- O( | Q8 |. vios::end -- 文件尾
2 G" j8 W5 v) |, B' ~1 u7 h K: Wios::cur -- 当前位置

文件读写

char s[50];

f.read(s, 49);

s[50] = '\0'; // 注意要自己加上字符串结束符

char *s = "hello";

f.write(s, strlen(s));

补充" w5 a5 j& j% b5 \# h! `6 s
记得读写完成后用f.close()关闭文件。

 

[cpp]  view plain  copy
  1. #include  
  2.   
  3.    
  4.   
  5.   
  6. #include  
  7.   
  8.    
  9.   
  10.   
  11. using namespace std;  
  12.   
  13.    
  14.   
  15.   
  16. //定义要删除的行号格式,下面定义的是型如: #0001 的行号  
  17.   
  18.    
  19.   
  20.   
  21. const int LINE_NUM_LENGTH = 5;  
  22.   
  23.    
  24.   
  25.   
  26. const char LINE_NUM_START = '#';  
  27.   
  28.    
  29.   
  30.   
  31. int main(int argc, char *argv[])  
  32.   
  33.    
  34.   
  35.   
  36. {  
  37.   
  38.    
  39.   
  40.   
  41. fstream f;  
  42.   
  43.    
  44.   
  45.   
  46. char *s = NULL;  
  47.   
  48.    
  49.   
  50.   
  51. int n;  
  52.   
  53.    
  54.   
  55.   
  56. for (int i = 1; i < argc; i++) {  
  57.   
  58.    
  59.   
  60.   
  61. 7 _+ T1 y; H4 q: c  H8 l  
  62. cout << "Processing file " << argv << "......";  
  63.   
  64.    
  65.   
  66.   
  67.   
  68.   C& K2 {1 Q7 V( U) U# A3 jf.open(argv, ios::in | ios::binary);  
  69.   
  70.    
  71.   
  72.   
  73.   
  74. 4 S% f% M3 v4 a: A: d5 Yif (!f.is_open()){  
  75.   
  76.    
  77.   
  78.   
  79.   
  80. , g  I6 {0 H8 v) c' v5 w: \cout << "CANNOT OPEN"<< endl;  
  81.   
  82.    
  83.   
  84.   
  85. ! `2 _& _% G1 D; y  
  86. continue;  
  87.   
  88.    
  89.   
  90.   
  91. 5 H9 _+ b: S8 Y8 E/ @% E: A  
  92. }  
  93.   
  94.    
  95.   
  96.   
  97.   
  98. % p6 T& I$ J  o2 v9 m$ f& J% Lf.seekg(0, ios::end);  
  99.   
  100.    
  101.   
  102.   
  103.   
  104. : J0 L' S& a1 t. Sn = f.tellg(); // 文件大小  
  105.   
  106.    
  107.   
  108.   
  109.   
  110. ) w+ H7 o2 [# e  }" |7 ss = new char[n+1];  
  111.   
  112.    
  113.   
  114.   
  115. * g: I2 ?+ a  |3 V, h  
  116. f.seekg(0, ios::beg);  
  117.   
  118.    
  119.   
  120.   
  121. 9 U7 `& L( T( e/ q$ g0 P3 C9 `7 v  
  122. f.read(s, n);  
  123.   
  124.    
  125.   
  126.   
  127. 0 }4 X+ h' P3 Z) Z+ L2 m  
  128. s[n] = '\0';  
  129.   
  130.    
  131.   
  132.   
  133. / R: L% B% o  ?0 g$ e" N3 T4 f! r  
  134. f.close();  
  135.   
  136.    
  137.   
  138.   
  139. 3 j( C$ ~$ a* Q* q4 o5 E, o4 C  
  140. // 采用一种简单的判断,遇到LINE_NUM_START后接一个数字,  
  141.   
  142.    
  143.   
  144.   
  145.   
  146. 5 J* v/ U$ q' y; _+ c// 则认为它是一个行号.  
  147.   
  148.    
  149.   
  150.   
  151. . x( W5 ^% g) d1 A* c+ e  
  152. for (int j = 0; j < n; j++) {  
  153.   
  154.    
  155.   
  156.   
  157.   
  158. ( a# v. A! u% ^) Hif (s[j] == LINE_NUM_START &&  
  159.   
  160.    
  161.   
  162.   
  163. 2 O, S' Q5 ^0 ~+ }8 h, q  
  164. (s[j+1] >= '0' && s[j+1] <= '9')) {  
  165.   
  166.    
  167.   
  168.   
  169. - V6 N0 _# m' H$ s6 P" ?# Y3 u  
  170. for (int k = j; k < j + LINE_NUM_LENGTH; k++)  
  171.   
  172.    
  173.   
  174.   
  175.   
  176. 7 r7 q% n6 D" R) I, E' V0 P( j* Us[k] = ' ';  
  177.   
  178.    
  179.   
  180.   
  181. ) b, d  x; I, ?$ m4 A) B1 J  
  182. }  
  183.   
  184.    
  185.   
  186.   
  187. 3 J" Z; x' S5 g, w( q- t- \# |  
  188. }  
  189.   
  190.    
  191.   
  192.   
  193.   
  194. ! a! n$ j9 u$ r9 i& nf.open(argv, ios::out | ios::binary);  
  195.   
  196.    
  197.   
  198.   
  199.   
  200. ) e: A5 S# w3 W# iif (!f.is_open()) {  
  201.   
  202.    
  203.   
  204.   
  205. ( n* k7 `* K! Z; i! l2 O) x  
  206. cout << "CANNOT OPEN" << endl;  
  207.   
  208.    
  209.   
  210.   
  211.   
  212. 1 ~2 W+ ?1 a4 p  f) ?8 A7 |/ Udelete[] s;  
  213.   
  214.    
  215.   
  216.   
  217.   
  218. 2 G) d- k& y9 p5 w4 q5 e/ c2 w( H( {, y6 R" ?+ F  
  219. continue;  
  220.   
  221.    
  222.   
  223.   
  224.   
  225. , {5 \" W2 R( i}  
  226.   
  227.    
  228.   
  229.   
  230. ( }$ r4 K# n: u3 v1 [/ w  
  231. f.write(s, n);  
  232.   
  233.    
  234.   
  235.   
  236. ) ~$ T& s7 i" x0 L% u  
  237. f.close();  
  238.   
  239.    
  240.   
  241.   
  242. 6 e5 d! {& z0 A& x( O2 t+ u  
  243. cout << "OK" << endl;  
  244.   
  245.    
  246.   
  247.   
  248. & R3 j% h: |; l; ]8 Y  P  
  249. delete[] s;  
  250.   
  251.    
  252.   
  253.   
  254. }  
  255.   
  256.    
  257.   
  258.   
  259. return 0;  
  260.   
  261.    
  262.   
  263.   
  264. }  
  265.   
  266.    
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值