迷你5207专属论坛

注册

 

发新话题 回复该主题

[C\C++] 一篇关于C++文件读写操作的文章【转】 [复制链接]

发表者
这篇文章大体简单的描述了C++中操作文件的方法,很易懂,推荐出来。

在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。
四、检测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个字节

fstream的用法
开一个文件
fstream f;
f.open("1.txt", ios::in | ios::binary);
if (!f.is_open()) // 检查文件是否成功打开
    cout < < "cannot open file." < < endl;
ios::in与ios::bianry均为int型,定义文件打开的方式。
ios::in -- 打开文件用于读。
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 -- 文件头    ios::end -- 文件尾    ios::cur -- 当前位置

文件读写
char s[50];
f.read(s, 49);
s[50] = '\0'; // 注意要自己加上字符串结束符

char *s = "hello";
f.write(s, strlen(s));

补充    记得读写完成后用f.close()关闭文件。

例子    下面的程序用于删除带有行号的源程序中的行号。

#include <iostream>
#include <fstream>
using namespace std;

//定义要删除的行号格式,下面定义的是型如: #0001 的行号
const int LINE_NUM_LENGTH = 5;
const char LINE_NUM_START = '#';

int main(int argc, char *argv[])
{
fstream f;
char *s = NULL;
int n;

for (int i = 1; i < argc; i++) {
    cout < < "Processing file " < < argv < < "......";
    f.open(argv, ios::in | ios::binary);
    if (!f.is_open()){
        cout < < "CANNOT OPEN" < < endl;
        continue;
    }
    f.seekg(0, ios::end);
    n = f.tellg(); // 文件大小
    s = new char[n+1];
    f.seekg(0, ios::beg);
    f.read(s, n);
    s[n] = '\0';
    f.close();

    // 采用一种简单的判断,遇到LINE_NUM_START后接一个数字,
    // 则认为它是一个行号.
    for (int j = 0; j < n; j++) {
        if (s[j] == LINE_NUM_START &&
            (s[j+1] >= '0' && s[j+1] <= '9')) {
            for (int k = j; k < j + LINE_NUM_LENGTH; k++)
                s[k] = ' ';
        }
    }

    f.open(argv, ios::out | ios::binary);
    if (!f.is_open()) {
        cout < < "CANNOT OPEN" < < endl;
        delete[] s;
        continue;
    }
    f.write(s, n);
    f.close();
    cout < < "OK" < < endl;
    delete[] s;
}
return 0;
}
c++中输出和输入导屏幕和键盘的类别声明包含再标题文件 <iostrream.h>中,而磁盘类文件的 I/O则声明再包含标题文件 <fstream.h>内。

输入和输出格式:

输出到磁盘  ofsteam 识别字(“文件名”)

从磁盘读文件 ifsteam 识别字("文件名“)

例如:

ofstream outfile("data.txt"); //写入到磁盘的data.txt中

格式化输入输出:

1 整数数据的输入输出

整数数据存储再磁盘内,每个文字各占一个字节。

例如:

#include <fstream.h>

#include <iostream.h>

#inlude <conio.h>

void main()

{

ofstream outfile("data.txt"); //写入文件

for(int i=0;i <10;i++)

  outfile < <i < <" ";    //空格是为了避免数值连接在一起加上去的,此文件大小为20字节

cout < <"ok,press a key!";

gerch();
}

程序执行后用记事本打开可以看到数据

0 1 2 3 4 5 6 7 8 9

同样读取文件语句为:

int data;

ifstream infile("data.txt");

for(int i=0;i <10;i++)

{

infile>>data ; //读数据的时候因为数据间有一个空格才能完整的读出,

cout < <data < <" "; //输出到屏幕,加上空格是为了分开数字

}

2 字符数据的输入

字符的输出方式以put(ch)为存入语句,读取语句为get(ch)

例如:

char str[]="hello this is a c++ programe!\n"

                    "i know this difference \n"

                    "and mocive";

ofstream outfile ("data.txt");

for(int i=0;i <strlen(Str);i++)

outfile.put(str);

读取:

char ch;

ifstream infile("data.txt");

while(infile)

{

infile.get(ch);

cout < <ch;

}

getch();

}

3 字符串数据的输入

数据多的时候读写速度比较快,输入时以整行字符串加上换行符号一次写入。读取的时候以语句getline(buffer,max),来读取整行数据,直到遇到换行符,每行结尾的\n并不读入,所以在 输出的时候需要加上换行符号,否则数据会连接在一起。

例子:

ofstream outfile("strdata.txt");

outfile < <"use your vote\n";

outfile < <"ouse your weise\n";

读取:

const MAX=80;

char buffer[MAX];

ifstream infile("strdata.txt");

while(infile)

{

infile.getline(buffer,MAX);

cout < <buffer < <endl;

}                  

4 浮点数

浮点数因为有小数点,在存储数据时与整数相同,只要每个数据加上一个空格就可以区隔相邻的数据
本主题由 皇帝 5207 于 2009-3-10 22:05:21 执行 主题分类 操作
分享 转发
相信与不相信都是矛盾的.  5207宣!欢迎您来到点滴论坛
TOP
沙发

谢谢!正在找这个呢:)
TOP
凳子

原帖由 guodongcc 于 2009-9-17 12:49:00 发表
谢谢!正在找这个呢:)


呵呵,我已经封装了一个读写器,在MiniNote里,有兴趣可以了解一下。
我写了篇小文说明了M8NoteReader的用法:
http://www.mini188.com/showtopic-1148.aspx
相信与不相信都是矛盾的.  5207宣!欢迎您来到点滴论坛
TOP
地板

很不错~~刚好看到来顶下(要验证码才能发消息有点烦)
TOP
5#

原帖由 love123i 于 2009-9-20 1:56:00 发表
很不错~~刚好看到来顶下(要验证码才能发消息有点烦)


这个主要是防止一些广告机器人的,没办法,我也不是经常在线。
相信与不相信都是矛盾的.  5207宣!欢迎您来到点滴论坛
TOP
6#

感觉论坛回复的人好少   不过版主还是很有激情    很高兴来到这里
TOP
7#

感觉论坛回复的人好少   不过版主还是很有激情    很高兴来到这里
loveyou13 发表于 2011-4-21 21:01:00
嗯。人气比较差。。。
相信与不相信都是矛盾的.  5207宣!欢迎您来到点滴论坛
TOP
发新话题 回复该主题