C 和 C++ 文件操作详解

来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html

来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html


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。

C 和 C++ 文件操作详解

C++ 通过以下几个类支持文件的输入输出:

  • ofstream: 写操作(输出)的文件类 (由ostream引申而来)
  • ifstream: 读操作(输入)的文件类(由istream引申而来)
  • fstream: 可同时读写操作的文件类 (由iostream引申而来)

打开文件(Open a file)

对这些类的一个对象所做的第一个操作通常就是将它和一个真正的文件联系起来,也就是说打开一个文件。被打开的文件在程序中由一个流对象(stream object)来表示 (这些类的一个实例) ,而对这个流对象所做的任何输入输出操作实际就是对该文件所做的操作。

1. 通过一个流对象调用open函数打开一个文件。我们使用它的成员函数open():void open (const char * filename, openmode mode);

这里filename 是一个字符串,代表要打开的文件名,mode 是以下标志符的一个组合: ios::in 为输入(读)而打开文件

文件的输入输出是从内存的角度看的:数据载入内存叫做输入,数据从内存到其他地方叫做输出。

  • ios::out 文件以输出(写)方式打开 
  • ios::in    文件以输入(读)方式打开
  • ios::ate 初始位置:文件尾
  • ios::app 所有输出附加在文件末尾
  • ios::trunc 如果文件已存在则先删除该文件
  • ios::binary 二进制方式

这些标识符可以被组合使用,中间以”或”操作符(|)间隔。例如,如果我们想要以二进制方式打开文件”example.bin” 来写入一些数据,我们可以通过以下方式调用成员函数open()来实现:

ofstream file;
file.open ("example.bin", ios::out | ios::app | ios::binary);

ofstream, ifstream 和 fstream所有这些类的成员函数open 都包含了一个默认打开文件的方式,这三个类的默认方式各不相同: 类 参数的默认方式

  • ofstream ios::out | ios::trunc
  • ifstream ios::in
  • fstream ios::in | ios::out

只有当函数被调用时没有声明方式参数的情况下,默认值才会被采用。如果函数被调用时声明了任何参数,默认值将被完全改写,而不会与调用参数组合。

2. 通过类对象构造函数打开文件。类ofstream, ifstream 和 fstream 的对象所进行的第一个操作通常都是打开文件,这些类都有一个构造函数可以直接调用open 函数,并拥有同样的参数。这样,我们就可以通过以下方式进行与上面同样的定义对象和打开文件的操作:
ofstream file ("example.bin", ios::out | ios::app | ios::binary);
例如:以二进制输入方式打开文件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");
以上 两种 打开文件的方式都是正确的。

通过调用成员函数is_open()来检查一个文件是否已经被顺利的打开:bool is_open()。它返回一个布尔(bool)值,为真(true)代表文件已经被顺利打开,假( false )则相反。

#include <fstream> 
ofstream //文件写操作 内存写入存储设备 
ifstream //文件读操作,存储设备读区到内存中 
fstream //读写操作,对打开的文件可进行读写操作
在fstream类中,成员函数open()实现打开文件的操作,从而将数据流和文件进行关联,通过ofstream,ifstream,fstream对象 进行对文件的读写操作

在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

ofstream out; 
out.open("Hello.txt", ios::in|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来定义。很多程序中,可能会碰到ofstream out("Hello.txt"), ifstream in("..."),fstream foi("...")这样的的使用,并没有显式的去调用open()函数就进行文件的操作,直接调用了其默认的打开方式,因为在stream类的构造函数中调用了open()函数,并拥有同样的构造函数,所以在这里可以直接使用流对象进行文件的操作,默认方式如下:
ofstream out("...", ios::out); 
ifstream in("...", ios::in); 
fstream foi("...", ios::in|ios::out); 
当使用默认方式进行对文件的操作时,你可以使用成员函数is_open()对文件是否打开进行验证

关闭文件(Closing a file)

当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。关闭文件需要调用成员函数close(),它负责将缓存中的数据排放出来并关闭文件。
void close ();    这个函数一旦被调用,原先的流对象(stream object)就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程(process)所有访问了。
为防止流对象被销毁时还联系着打开的文件,析构函数(destructor)将会自动调用关闭函数close。

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

读写文件

读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,

下要就详细的介绍这两种方式

文本文件(Text mode files)

类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。
一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin 和 cout)来进行输入输出。如下面的例题所示,我们使用重载的插入操作符

文本文件的读写很简单:用插入器(>>)从文件输入。假设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。

类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。
一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin 和 cout)来进行输入输出。如下面的例题所示,我们使用重载的插入操作符<<:

// writing on a text file 
 #include <fiostream.h> 
 int main () { 
   ofstream out("out.txt"); 
   if (out.is_open())  
  { 
     out << "This is a line.\n"; 
     out << "This is another line.\n"; 
     out.close(); 
   } 
   return 0; 
 } 
//结果: 在out.txt中写入: 
This is a line. 
This is another line
从文件中读入数据也可以用与 cin>>的使用同样的方法:
// reading a text file 
  #include <iostream.h> 
  #include <fstream.h> 
  #include <stdlib.h> 
    
  int main () { 
    char buffer[256]; 
    ifstream in("test.txt"); 
    if (! in.is_open()) 
    { cout << "Error opening file"; exit (1); } 
    while (!in.eof() ) 
    { 
      in.getline (buffer,100); 
      cout << buffer << endl; 
    } 
    return 0; 
  } 
  //结果 在屏幕上输出 
  This is a line. 
  This is another line
例子中读入一个文本文件的内容,然后将它打印到屏幕上。注意我们使用了一个新的成员函数叫做eof ,它是ifstream 从类 ios 中继承过来的,当到达文件末尾时返回true 。

二进制文件(Binary files)

在二进制文件中,使用<< 和>>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。

文件流包括两个为顺序读写数据特殊设计的成员函数:write 和 read。第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。而read 是istream 的一个成员函数,被ifstream 所继承。类 fstream 的对象同时拥有这两个函数。它们的原型是:

write ( char * buffer, streamsize size );
read ( char * buffer, streamsize size );

这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。

// reading binary file
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
    const char * filename = "example.txt";
    char * buffer;
    long size;
    ifstream file(filename, ios::in|ios::binary|ios::ate);
    size = file.tellg();
    file.seekg(0, ios::beg);
    buffer = new char [size];
    file.read(buffer, size);
    file.close();
    cout <<"the complete file is in a buffer";
    delete[] buffer;
    return 0;
}
//The complete file is in a buffer

①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();

状态标志符的验证(Verification of state flags)

除了eof()以外,还有一些验证流的状态的成员函数(所有都返回bool型返回值):

bad():如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。
fail():除了与bad() 同样的情况下会返回 true 以外,加上格式错误时也返回true ,例如当想要读入一个整数,而获得了一个字母的时候。
eof():如果读文件到达文件末尾,返回true。
good():这是最通用的:如果调用以上任何一个函数返回true 的话,此函数返回 false 。

要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。

缓存和同步(Buffers and Synchronization)

当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。

当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:

1. 当文件被关闭时: 在文件被关闭之前,所有还没有被完全写出或读取的缓存都将被同步。
2. 当缓存buffer 满时:缓存Buffers 有一定的空间限制。当缓存满时,它会被自动同步。
3. 控制符明确指明:当遇到流中某些特定的控制符时,同步会发生。这些控制符包括:flush 和endl。
4. 明确调用函数sync(): 调用成员函数sync() (无参数)可以引发立即同步。这个函数返回一个int 值,等于-1 表示流没有联系的缓存或操作失败

检测 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个字节

获得和设置流指针(get and put stream pointers)

所有输入/输出流对象(i/o streams objects)都有至少一个流指针:

ifstream, 类似istream, 有一个被称为get pointer的指针,指向下一个将被读取的元素。
ofstream, 类似 ostream, 有一个指针 put pointer ,指向写入下一个元素的位置。
fstream, 类似 iostream, 同时继承了get 和 put
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:

tellg() 和 tellp()

这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get 流指针的位置 (用tellg) 或 put 流指针的位置(用tellp).
seekg() 和seekp()

这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型:

seekg ( pos_type position );
seekp ( pos_type position );
使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。
seekg ( off_type offset, seekdir direction );
seekp ( off_type offset, seekdir direction );
使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:
ios::beg 从流开始位置计算的位移
ios::cur 从流指针当前位置开始计算的位移
ios::end 从流末尾处开始计算的位移

流指针 get 和 put 的值对文本文件(text file)和二进制文件(binary file)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。由于这个原因,建议对以文本文件模式打开的文件总是使用seekg 和 seekp的第一种原型,而且不要对tellg 或 tellp 的返回值进行修改。对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。

以下例子使用这些函数来获得一个二进制文件的大小:

// obtaining file size
#include <iostream>
#include <fstream>
using namespace std;

int main ()
{
    const char * filename = "example.txt";
    long l,m;
    ifstream file(filename, ios::in|ios::binary);
    l = file.tellg();
    file.seekg(0, ios::end);
    m = file.tellg();
    file.close();
    cout <<"size of "<< filename;
    cout <<" is "<< (m-l)<<" bytes.\n";
    return 0;
}
//size of example.txt is 40 bytes.

C语言文件操作详解

基于C的文件操作

在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。

一、流式文件操作:这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:

typedef struct
{
    short           level;          /* fill/empty level of buffer */
    unsigned        flags;          /* File status flags    */
    char            fd;             /* File descriptor      */
    unsigned char   hold;           /* Ungetc char if no buffer */
    short           bsize;          /* Buffer size          */
    unsigned char   *buffer;        /* Data transfer buffer */
    unsigned char   *curp;          /* Current active pointer */
    unsigned        istemp;         /* Temporary file indicator */
    short           token;          /* Used for validity checking */
}FILE;    /* This is the FILE object */
FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行。

C语言中没有输入输出语句,所有的输入输出功能都用 ANSI C提供的一组标准库函数来实现。文件操作标准库函数有:

      文件的打开操作 fopen 打开一个文件
      文件的关闭操作 fclose 关闭一个文件
      文件的读写操作 fgetc 从文件中读取一个字符
              fputc 写一个字符到文件中去
              fgets 从文件中读取一个字符串
              fputs 写一个字符串到文件中去
              fprintf 往文件中写格式化数据
              fscanf 格式化读取文件中数据
              fread 以二进制形式读取文件中的数据
              fwrite 以二进制形式写数据到文件中去
              getw 以二进制形式读取一个整数
              putw 以二进制形式存贮一个整数
    文件状态检查函数  feof 文件结束
              ferror 文件读/写出错
              clearerr 清除文件错误标志
              ftell 了解文件指针的当前位置

             文件定位函数 rewind 反绕
              fseek 随机定位

文件的打开

 1.函数原型:FILE *fopen(char *pname,char *mode)

 2.功能说明
   按照mode 规定的方式,打开由pname指定的文件。若找不到由pname指定的相应文件,就按以下方式之一处理:
       (1) 此时如mode 规定按写方式打开文件,就按由pname指定的名字建立一个新文件;
       (2) 此时如mode 规定按读方式打开文件,就会产生一个错误。

        打开文件的作用是:
        (1)分配给打开文件一个FILE 类型的文件结构体变量,并将有关信息填入文件结构体变量;
        (2)开辟一个缓冲区;
        (3)调用操作系统提供的打开文件或建立新文件功能,打开或建立指定文件;
        FILE *:指出fopen是一个返回文件类型的指针函数;

 3.参数说明

pname:是一个字符指针,指向要打开的文件名。
mode:是一个指向文件处理方式字符串的字符指针。
字符串 含义
"r" 打开只读文件,该文件必须存在。
"w" 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
"a" 以追加方式打开只写文件。文件不存在建立该文件,如文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
"r+" 以读/写方式打开文件,该文件必须存在。如无文件则出错
"w+" 以读/写方式打开文件,若文件存在则文件长度清为零,即文件内容清空。若文件不存在则建立该文件。

上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b 字符用来告诉函数库打开的文件为二进制文件,而非纯文字文件。不过在POSIX系统,包含Linux都会忽略该字符。由fopen()所建立的新文件会具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)权限,此文件权限也会参考umask值。
返回值 文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。
附加说明 一般而言,开文件后会作一些文件读取或写入的动作,若开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。

  一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符''\n'',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。

  系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。
  我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。
  此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。

 4.返回值
   正常返回:被打开文件的文件指针。
   异常返回:NULL,表示打开操作不成功。

//定义一个名叫fp文件指针
FILE *fp;
//判断按读方式打开一个名叫test的文件是否失败
if((fp=fopen("test","r")) == NULL)//打开操作不成功
{
    printf("The file can not be opened.\n");     
    exit(1);//结束程序的执行
}
FILE *fp;
if(fp=fopen("123.456","wb"))
    puts("打开文件成功");
else
    puts("打开文件成败");

要说明的是:C语言将计算机的输入输出设备都看作是文件。例如,键盘文件、屏幕文件等。ANSI C标准规定,在执行程序时系统先自动打开键盘、屏幕、错误三个文件。这三个文件的文件指针分别是:标准输入stdin、标准输出stdout和标准出错 stderr。

freopen(打开文件)

相关函数 fopen,fclose
表头文件 #include<stdio.h>
定义函数 FILE * freopen(const char * path,const char * mode,FILE * stream);
函数说明 参数path字符串包含欲打开的文件路径及文件名,参数mode请参考fopen()说明。参数stream为已打开的文件指针。Freopen()会将原stream所打开的文件流关闭,然后打开参数path的文件。
返回值 文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中。

#include<stdio.h>
main()
{
FILE * fp;
fp=fopen(“/etc/passwd”,”r”);
fp=freopen(“/etc/group”,”r”,fp);
fclose(fp);
}

文件的关闭

1. 函数原型:int fclose(FILE *fp);

2. 功能说明
  关闭由fp指出的文件。此时调用操作系统提供的文件关闭功能,关闭由fp->fd指出的文件;释放由fp指出的文件类型结构体变量;返回操作结果,即0或EOF。

3. 参数说明
  fp:一个已打开文件的文件指针。

4. 返回值
  正常返回:0。
  异常返回:EOF,表示文件在关闭时发生错误。
例如:

int n=fclose(fp);

文件的读写操作

1. 从文件中读取一个字符

  1. 函数原型:int fgetc(FILE *fp);

  2. 功能说明:从fp所指文件中读取一个字符。   

  3. 参数说明:fp:这是个文件指针,它指出要从中读取字符的文件。   

  4. 返回值
    正常返回: 返回读取字符的代码。
    非正常返回:返回EOF。例如,要从"写打开"文件中读取一个字符时,会发生错误而返回一个EOF。

//显示指定文件的内容。

//程序名为:display.c
//执行时可用:display filename1 形式的命令行运行。显示文件filename1中的内容。例如,执行命令行display display.c将在屏幕上显示display的原代码。

//File display program.
#include <stdio.h>
void main(int argc,char *argv[]) //命令行参数
{
    int ch;//定义文件类型指针
    FILE *fp;//判断命令行是否正确
    if(argc!=2)
    {
        printf("Error format,Usage: display filename1\n");
        return; //键入了错误的命令行,结束程序的执行
    }
    //按读方式打开由argv[1]指出的文件
    if((fp=fopen(argv[1],"r"))==NULL)
    {
        printf("The file <%s> can not be opened.\n",argv[1]);//打开操作不成功
        return;//结束程序的执行
    }
    //成功打开了argv[1]所指文件
    ch=fgetc(fp); //从fp所指文件的当前指针位置读取一个字符
    while(ch!=EOF) //判断刚读取的字符是否是文件结束符
    {
        putchar(ch); //若不是结束符,将它输出到屏幕上显示
        ch=fgetc(fp); //继续从fp所指文件中读取下一个字符
    } //完成将fp所指文件的内容输出到屏幕上显示
    fclose(fp); //关闭fp所指文件
}

2. 写一个字符到文件中去

1. 函数原型:int fputc(int ch,FILE *fp)

2. 功能说明:把ch中的字符写入由fp指出的文件中去。 

3. 参数说明
  ch:是一个整型变量,内存要写到文件中的字符(C语言中整型量和字符量可以通用)。
  fp:这是个文件指针,指出要在其中写入字符的文件。

4. 返回值
  正常返回: 要写入字符的代码。
  非正常返回:返回EOF。例如,要往"读打开"文件中写一个字符时,会发生错误而返回一个EOF。

//将一个文件的内容复制到另一个文件中去。

//程序名为:copyfile.c
//执行时可用:copyfile filename1 filename2形式的命令行运行,将文件filename1中的内容复制到文件filename2中去。
//file copy program.
#include <stdio.h>
void main(int argc,char *argv[]) //命令行参数
{
    int ch;
    FILE *in,*out; //定义in和out两个文件类型指针
    if(argc!=3) //判断命令行是否正确
    {
        printf("Error in format,Usage: copyfile filename1 filename2\n");
        return; //命令行错,结束程序的执行
    }
    //按读方式打开由argv[1]指出的文件
    if((in=fopen(argv[1],"r"))==NULL)
    {
        printf("The file <%s> can not be opened.\n",argv[1]);
        return; //打开失败,结束程序的执行
    }
    //成功打开了argv[1]所指文件,再
    //按写方式打开由argv[2]指出的文件
    if((out=fopen(argv[2],"w"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[2]);
        return; //打开失败,结束程序的执行
    }
    //成功打开了argv[2]所指文件
    ch=fgetc(in); //从in所指文件的当前指针位置读取一个字符
    while(ch!=EOF) //判断刚读取的字符是否是文件结束符
    {
        fputc(ch,out); //若不是结束符,将它写入out所指文件
        ch=fgetc(in); //继续从in所指文件中读取下一个字符
    } //完成将in所指文件的内容写入(复制)到out所指文件中
    fclose(in); //关闭in所指文件
    fclose(out); //关闭out所指文件
}
//按十进制和字符显示文件代码,若遇不可示字符就用井号"#"字符代替之。
//程序名为:dumpf.c
//执行时可用:dumpf filename1 形式的命令行运行。
// File dump program.
#include <stdio.h>
void main(int argc,char *argv[])
{
    char str[9];
    int ch,count,i;
    FILE *fp;
    if(argc!=2)
    {
        printf("Error format,Usage: dumpf filename\n");
        return;
    }
    if((fp=fopen(argv[1],"r"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    count=0;
    do{
        i=0;
        //按八进制输出第一列,作为一行八个字节的首地址
        printf("%06o: ",count*8);
        do{
            // 从打开的文件中读取一个字符
            ch=fgetc(fp);
            // 按十进制方式输出这个字符的ASCII码
            printf("%4d",ch);
            // 如果是不可示字符就用"#"字符代替
            if(ch<' '||ch>'~') str[i]='#';
            // 如果是可示字符,就将它存入数组str以便形成字符串
            else str[i]=ch;
            // 保证每一行输出八个字符
            if(++i==8) break;
        }while(ch!=EOF); // 遇到文件尾标志,结束读文件操作
        str[i]='\0'; // 在数组str加字符串结束标志
        for(;i<8;i++) printf(" "); // 一行不足八个字符用空格填充
        printf(" %s\n",str); // 输出字符串
        count++; // 准备输出下一行
    }while(ch!=EOF); // 直到文件结束
    fclose(fp); // 关闭fp所指文件
}

3. 从文件中读取一个字符串

1. 函数原型:char *fgets(char *str,int n,FILE *fp)
2. 功能说明
  从由fp指出的文件中读取n-1个字符,并把它们存放到由str指出的字符数组中去,最后加上一个字符串结束符'\0'。
3. 参数说明
  str:接收字符串的内存地址,可以是数组名,也可以是指针。
  n: 指出要读取字符的个数。
  fp:这是个文件指针,指出要从中读取字符的文件。
4. 返回值

正常返回:返回字符串的内存首地址,即str的值。
非正常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。例如,要从"写打开"文件中读取字符串,将
发生错误而返回一个NULL值。

4. 写一个字符串到文件中去

1. 函数原型:int fputs(char *str,FILE *fp)

2. 功能说明
  把由str指出的字符串写入到fp所指的文件中去。
3. 参数说明
  str:指出要写到文件中去的字符串。
  fp:这是个文件指针,指出字符串要写入其中的文件。
4. 返回值
  正常返回: 写入文件的字符个数,即字符串的长度。
  非正常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。例如,要往一个"读打开" 文件中写字符串时,
会发生错误而返回一个NULL值。

//以下程序将一个文件的内容附加到另一个文件中去。
//程序名:linkfile.c
//执行时可用:linkfile filename1 filename2形式的命令行运行,将文件filename2的内容附加在文件filename1之后。
// file linked program.
#include <stdio.h>
#define SIZE 512
void main(int argc,char *argv[])
{
    char buffer[SIZE];
    FILE *fp1,*fp2;
    if(argc!=3)
    {
        printf("Usage: linkfile filename1 filename2\n");
        return;
    }
    // 按追加方式打开argv[1] 所指文件
    if((fp1=fopen(argv[1],"a"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    if((fp2=fopen(argv[2],"r"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[2]);
        return;
    }
    // 读入一行立即写出,直到文件结束
    while(fgets(buffer,SIZE,fp1)!=NULL)
        printf("%s\n",buffer);
    while(fgets(buffer,SIZE,fp2)!=NULL)
        fputs(buffer,fp1);
    fclose(fp1);
    fclose(fp2);
    if((fp1=fopen(argv[1],"r"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    while(fgets(buffer,SIZE,fp1)!=NULL)
        printf("%s\n",buffer);
    fclose(fp1);
}

5. 往文件中写格式化数据

1.函数原型:int fprintf(FILE *fp,char *format,arg_list)

2.功能说明
  将变量表列(arg_list)中的数据,按照format指出的格式,写入由fp指定的文件。fprintf()函数与printf()函数的功能相同,只是printf()函数是将数据写入屏幕文件(stdout)。
3.参数说明
  fp:这是个文件指针,指出要将数据写入的文件。
  format:这是个指向字符串的字符指针,字符串中含有要写出数据的格式,所以该字符串成为格式串。格式串描述的规则与printf()函数中的格式串相同。
arg_list:是要写入文件的变量表列,各变量之间用逗号分隔。
4.返回值:无。

// 下列程序的执行文件为display.exe,执行时键入命令行:
//   display [-i][-s] filename
// 下面的表格列出了命令行参数的含义及其功能:

//存储文件名:save.txt
//程序代码如下:
// file display program.
#include <stdio.h>
void main()
{
    char name[10];
    int nAge,nClass;
    long number;
    FILE *fp;
    if((fp=fopen("student.txt","w"))==NULL)
    {
        printf("The file %s can not be opened.\n","student.txt");
        return;
    }
    fscanf(stdin,"%s %d %d %ld",name,&nClass,&nAge,&number);
    fprintf(fp,"%s %5d %4d %8ld",name,nClass,nAge,number);
    fclose(fp);
    if((fp=fopen("student.txt","r"))==NULL)
    {
        printf("The file %s can not be opened.\n","student.txt");
        return;
    }
    fscanf(fp,"%s %d %d %ld",name,&nClass,&nAge,&number);
    printf("name nClass nAge number\n");
    fprintf(stdout,"%-10s%-8d%-6d%-8ld\n",name,nClass,nAge,number);
    fclose(fp);
}

fscanf  从一个流中执行格式化输入
表头文件:#include<stdio.h>
函数原型:int fscanf(FILE *stream, char *format[,argument...]);
FILE* 一个FILE型的指针
char* 格式化输出函数,和scanf里的格式一样
返回值:成功时返回转换的字节数,失败时返回一个负数
fp = fopen("/local/test.c","a+");
fscanf(fp,"%s",str);

fdopen(将文件描述词转为文件指针)
相关函数 fopen,open,fclose
表头文件 #include<stdio.h>
定义函数 FILE * fdopen(int fildes,const char * mode);
函数说明 fdopen()会将参数fildes 的文件描述词,转换为对应的文件指针后返回。参数mode 字符串则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。关于mode 字符串格式请参考fopen()。
返回值 转换成功时返回指向该流的文件指针。失败则返回NULL,并把错误代码存在errno中。

#include<stdio.h>
main()
{
FILE * fp =fdopen(0,”w+”);
fprintf(fp,”%s/n”,”hello!”);
fclose(fp);
}
执行 hello!

fflush(更新缓冲区)
相关函数 write,fopen,fclose,setbuf
表头文件 #include<stdio.h>
定义函数 int fflush(FILE* stream);
函数说明 fflush()会强迫将缓冲区内的数据写回参数stream指定的文件中。如果参数stream为NULL,fflush()会将所有打开的文件数据更新。
返回值 成功返回0,失败返回EOF,错误代码存于errno中。
错误代码 EBADF 参数stream 指定的文件未被打开,或打开状态为只读。其它错误代码参考write()。

fileno(返回文件流所使用的文件描述词)
相关函数 open,fopen
表头文件 #include<stdio.h>
定义函数 int fileno(FILE * stream);
函数说明 fileno()用来取得参数stream指定的文件流所使用的文件描述词。
返回值 返回文件描述词。

#include<stdio.h>
main()
{
FILE * fp;
int fd;
fp=fopen(“/etc/passwd”,”r”);
fd=fileno(fp);
printf(“fd=%d/n”,fd);
fclose(fp);
}
执行 fd=3


6. 以二进制形式读取文件中的数据

1. 函数原型:int fread(void *buffer,unsigned sife,unsigned count,FILE *fp)

2. 功能说明
  从由fp指定的文件中,按二进制形式将sife*count个数据读到由buffer指出的数据区中。
3. 参数说明

buffer:这是一个void型指针,指出要将读入数据存放在其中的存储区首地址。
sife:指出一个数据块的字节数,即一个数据块的大小尺寸。
count:指出一次读入多少个数据块(sife)。
fp:这是个文件指针,指出要从其中读出数据的文件。

4.返回值

  正常返回:实际读取数据块的个数,即count。

  异常返回:如果文件中剩下的数据块个数少于参数中count指出的个数,或者发生了错误,返回0值。此时可以用feof()和ferror()来判定到底出现了什么情况。

#include<stdio.h>
#define nmemb 3
struct test
{
    char name[20];
    int size;
}s[nmemb];
int main()
{
    FILE * stream;
    int i;
    stream = fopen(“/tmp/fwrite”,”r”);
    fread(s,sizeof(struct test),nmemb,stream);
    fclose(stream);
    for(i=0;i<nmemb;i++)
        printf("name[%d]=%-20s:size[%d]=%d/n",i,s.name,i,s.size);
    return 0;
}

执行结果:
name[0]=Linux! size[0]=6
name[1]=FreeBSD! size[1]=8
name[2]=Windows2000 size[2]=11



7. 以二进制形式写数据到文件中去

1. 函数原型:int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp)
2. 功能说明
  按二进制形式,将由buffer指定的数据缓冲区内的sife*count个数据写入由fp指定的文件中去。
3. 参数说明
buffer:这是一个void型指针,指出要将其中数据输出到文件的缓冲区首地址。
sife:指出一个数据块的字节数,即一个数据块的大小尺寸。
count:一次输出多少个数据块(sife)。
fp:这是个文件指针,指出要从其中读出数据的文件。

4.返回值

  正常返回:实际输出数据块的个数,即count。

  异常返回:返回0值,表示输出结束或发生了错误。

#include <stdio.h>
#define SIZE 4
struct worker
{ int number;
    char name[20];
    int age;
};
void main()
{
    struct worker wk;
    int n;
    FILE *in,*out;
    if((in=fopen("file1.txt","rb"))==NULL)
    {
        printf("The file %s can not be opened.\n","file1.txt");
        return;
    }
    if((out=fopen("file2.txt","wb"))==NULL)
    {
        printf("The file %s can not be opened.\n","file2.txt");
        return;
    }
    while(fread(&wk,sizeof(struct worker),1,in)==1)
        fwrite(&wk,sizeof(struct worker),1,out);
    fclose(in);
    fclose(out);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define set_s(x,y) {strcpy(s[x].name,y);s[x].size=strlen(y);}
#define nmemb 3
struct test
{
    char name[20];
    int size;
}s[nmemb];

main()
{
    FILE * stream;
    set_s(0,"Linux!");
    set_s(1,"FreeBSD!");
    set_s(2,"Windows2000.");
    stream=fopen("fwrite","w");
    fwrite(s,sizeof(struct test),nmemb,stream);
    fclose(stream);
}

执行 参考fread()。


8. 以二进制形式读取一个整数

1. 函数原型:int getw(FILE *fp)

2. 功能说明
  从由fp指定的文件中,以二进制形式读取一个整数。
3. 参数说明
  fp:是文件指针。
4. 返回值
  正常返回:所读取整数的值。
  异常返回:返回EOF,即-1。由于读取的整数值有可能是-1,所以必须用feof()或ferror()来判断是到了文件结束,还是出现了一个出错。

#include <stdio.h>
void main(int argc,char *argv[])
{
    int i,sum=0;
    FILE *fp;
    if(argc!=2)
    {
        printf("Command error,Usage: readfile filename\n");
        exit(1);
    }
    if(!(fp=fopen(argv[1],"rb")))
    {
        printf("The file %s can not be opened.\n",argv[1]);
        exit(1);
    }
    for(i=1;i<=10;i++) sum+=getw(fp);
    printf("The sum is %d\n",sum);
    fclose(fp);
}

9. 以二进制形式存贮一个整数

1.函数原型:int putw(int n,FILE *fp)

2. 功能说明
 以二进制形式把由变量n指出的整数值存放到由fp指定的文件中。
3. 参数说明
 n:要存入文件的整数。
 fp:是文件指针。
4. 返回值
 正常返回:所输出的整数值。
 异常返回:返回EOF,即-1。由于输出的整数值有可能是-1,所以必须用feof()或ferror()来判断是到了文件结束,还是出现了一个出错。

#include <stdio.h>
void main(int argc,char *argv[])
{
    int i;
    FILE *fp;
    if(argc!=2)
    {
        printf("Command error,Usage: writefile filename\n");
        return;
    }

    if(!(fp=fopen(argv[1],"wb")))
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    for(i=1;i<=10;i++) printf("%d\n", putw(i,fp));
    fclose(fp);
}

文件状态检查

1. 文件结束

(1) 函数原型:int feof(FILE *fp)

(2) 功能说明
   该函数用来判断文件是否结束。
(3) 参数说明
   fp:文件指针。
(4) 返回值
   0:假值,表示文件未结束。
   1:真值,表示文件结束。

#include <stdio.h>
void main(int argc,char *argv[])
{
    FILE *in,*out;
    char ch;
    if(argc!=3)
    {
        printf("Usage: copyfile filename1 filename2\n");
        return;
    }
    if((in=fopen(argv[1],"rb"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    if((out=fopen(argv[2],"wb"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[2]);
        return;
    }
    while(!feof(in))
    {
        ch=fgetc(in);
        if(ferror(in))
        {
            printf("read error!\n");
            clearerr(in);
        }
        else
        {
            fputc(ch,out);
            if(ferror(out))
            {
                printf("write error!\n");
                clearerr(out);
            }
        }
    }
    fclose(in);
    fclose(out);
}

2. 文件读/写出错

(1) 函数原型:int ferror(FILE *fp)

(2) 功能说明
   检查由fp指定的文件在读写时是否出错。
(3) 参数说明
   fp:文件指针。
(4) 返回值
   0:假值,表示无错误。
   1:真值,表示出错。

3. 清除文件错误标志

(1) 函数原型:void clearerr(FILE *fp)

(2) 功能说明
   清除由fp指定文件的错误标志。
(3) 参数说明
   fp:文件指针。
(4) 返回值:无。

#include <stdio.h>
void main(int argc,char *argv[])
{
    FILE *in,*out;
    char ch;
    if(argc!=3)
    {
        printf("Usage: copyfile filename1 filename2\n");
        return;
    }
    if((in=fopen(argv[1],"rb"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[1]);
        return;
    }
    if((out=fopen(argv[2],"wb"))==NULL)
    {
        printf("The file %s can not be opened.\n",argv[2]);
        return;
    }
    while(!feof(in))
    {
        ch=fgetc(in);
        if(ferror(in))
        {
            printf("read error!\n");
            clearerr(in);
        }
        else
        {
            fputc(ch,out);
            if(ferror(out))
            {
                printf("write error!\n");
                clearerr(out);
            }
        }
    }
    fclose(in);
    fclose(out);
}

4. 了解文件指针的当前位置

(1) 函数原型:long ftell(FILE *fp)

(2) 功能说明
   取得由fp指定文件的当前读/写位置,该位置值用相对于文件开头的位移量来表示。
(3) 参数说明
   fp:文件指针。
(4) 返回值
   正常返回:位移量(这是个长整数)。
   异常返回:-1,表示出错。
(5) 实例

文件定位

1. 反绕

(1) 函数原型:void rewind(FILE *fp)

(2) 功能说明
   使由文件指针fp指定的文件的位置指针重新指向文件的开头位置。
(3) 参数说明
   fp:文件指针。
(4) 返回值:无。

#include <stdio.h>
void main()
{
    FILE *in,*out;
    in=fopen("filename1","r");
    out=fopen("filename2","w");
    while(!feof(in)) fputc(fgetc(in),out);
    rewind(out);
    while(!feof(in)) putchar(fgetc(in));
    fclose(in);
    fclose(out);
}

2. 随机定位:移动文件流的读写位置

(1) 函数原型:int fseek(FILE *fp,long offset,int base)

(2) 功能说明
   使文件指针fp移到基于base的相对位置offset处。
(3)参数说明
   fp:文件指针。
   offset:相对base的字节位移量。这是个长整数,用以支持大于64KB的文件。
   base:文件位置指针移动的基准位置,是计算文件位置指针位移的基点。ANSI C定义了base的可能取值,以及这些取值的符号常量。

(4)返回值

  正常返回:当前指针位置。
  异常返回:-1,表示定位操作出错。

下列是较特别的使用方式:
1) 欲将读写位置移动到文件开头时:fseek(FILE *stream,0,SEEK_SET);
2) 欲将读写位置移动到文件尾时:fseek(FILE *stream,0,0SEEK_END);
返回值 当调用成功时则返回0,若有错误则返回-1,errno会存放错误代码。
附加说明 fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。

#include <stdio.h>
#include <string.h>
struct std_type
{
    int num;
    char name[20];
    int age;
    char class;
}stud;
int cstufile()
{
    int i;
    FILE *fp;
    if((fp=fopen("stufile","wb"))==NULL)
    {
        printf("The file can't be opened for write.\n");
        return 0;
    }
    for(i=1;i<=100;i++)
    {
        stud.num=i;
        strcpy(stud.name,"aaaa");
        stud.age=17;
        stud.class='8';
        fwrite(&stud,sizeof(struct std_type),1,fp);
    }
    fclose(fp);
    return 1;
}
void main()
{
    int n;
    FILE *fp;
    if(cstufile()==0) return;
    if((fp=fopen("stufile","rb"))==NULL)
    {
        printf("The file can not be opened.\n");
        return;
    }
    for(n=0;n<100;n+=2)
    {
        fseek(fp,n*sizeof(struct std_type),SEEK_SET);
        fread(&stud,sizeof(struct std_type),1,fp);
        printf("%10d%20s%10d%4c\n",stud.num,stud.name,stud.age,stud.class);
    }
    fclose(fp);
}

#include <stdio.h>
#include <stdlib.h>

#include<stdio.h>
void main()
{
    FILE * stream;
    long offset;
    fpos_t pos;
    stream=fopen(“/etc/passwd”,”r”);
    fseek(stream,5,SEEK_SET);
    printf("offset=%d/n",ftell(stream));
    rewind(stream);
    fgetpos(stream,&pos);
    printf("offset=%d/n",pos);
    pos=10;
    fsetpos(stream,&pos);
    printf("offset = %d/n",ftell(stream));
    fclose(stream);
}
执行 结果
offset = 5
offset =0
offset=10

ftell(取得文件流的读取位置)
相关函数 fseek,rewind,fgetpos,fsetpos
表头文件 #include<stdio.h>
定义函数 long ftell(FILE * stream);
函数说明 ftell()用来取得文件流目前的读写位置。参数stream为已打开的文件指针。
返回值 当调用成功时则返回目前的读写位置,若有错误则返回-1,errno会存放错误代码。
错误代码 EBADF 参数stream无效或可移动读写位置的文件流。
范例 参考fseek()。

关于exit()函数

1. 函数原型:void exit(int status)

2. 功能说明:exit()函数使程序立即终止执行,同时将缓冲区中剩余的数据输出并关闭所有已经打开的文件。
3. 参数说明:status:为0值表示程序正常终止,为非0值表示一个定义错误。
4. 返回值:无。

* 关于feof()函数

1. 函数原型:int feof(FILE *fp)
2. 功能说明
   在文本文件(ASCII文件)中可以用值为-1的符号常量EOF来作为文件的结束符。但是在二进制文件中-1往往可能是一个有意义的数据,因此不能用它 来作为文件的结束标志。为了能有效判别文件是否结束,ANSI C提供了标准函数feof(),用来识别文件是否结束。
3. 参数说明:fp:文件指针。
4. 返回值
  返回为非0值:已到文件尾。
  返回为0值:表示还未到文件尾。

C语言的直接I\O文件操作

这是C提供的另一种文件操作,它是通过直接存/取文件来完成对文件的处理,而上篇所说流式文件操作是通过缓冲区来进行;流式文件操作是围绕一个FILE指针来进行,而此类文件操作是围绕一个文件的“句柄”来进行,什么是句柄呢?它是一个整数,是系统用来标识一个文件(在WINDOWS中,句柄的概念扩展到所有设备资源的标识)的唯一的记号。此类文件操作常用的函数如下表,这些函数及其所用的一些符号在io.h和fcntl.h中定义,在使用时要加入相应的头文件。

函数             说明
open()         打开一个文件并返回它的句柄
close()        关闭一个句柄
lseek()        定位到文件的指定位置
read()         块读文件
write()        块写文件
eof()          测试文件是否结束
filelength()   取得文件长度
rename()       重命名文件
chsize()       改变文件长度


1.open()
  打开一个文件并返回它的句柄,如果失败,将返回一个小于0的值,原型是int open(const char *path, int access [, unsigned mode]); 参数path是要打开的文件名,access是打开的模式,mode是可选项。表示文件的属性,主要用于UNIX系统中,在DOS/WINDOWS这个参数没有意义。其中文件的打开模式如下表。
符号 含义 符号 含义 符号 含义
O_RDONLY 只读方式 O_WRONLY 只写方式 O_RDWR 读/写方式
O_NDELAY 用于UNIX系统 O_APPEND 追加方式 O_CREAT 如果文件不存在就创建
O_TRUNC 把文件长度截为0 O_EXCL 和O_CREAT连用,如果文件存在返回错误 O_BINARY 二进制方式 O_TEXT 文本方式 
对于多个要求,可以用"|"运算符来连接,如O_APPEND|O_TEXT表示以文本模式和追加方式打开文件。
例:inthandle=open("c:\\msdos.sys",O_BINARY|O_CREAT|O_WRITE)

2.close()
关闭一个句柄,原型是int close(int handle);如果成功返回0
例:close(handle)

3.lseek()
  定位到指定的位置,原型是:long lseek(int handle,long offset, int fromwhere);参数offset是移动的量,fromwhere是移动的基准位置,取值和前面讲的fseek()一样,SEEK_SET:文件首部;SEEK_CUR:文件当前位置;SEEK_END:文件尾。此函数返回执行后文件新的存取位置。
例:
  lseek(handle,-1234L,SEEK_CUR);//把存取位置从当前位置向前移动1234个字节。
  x=lseek(hnd1,0L,SEEK_END);//把存取位置移动到文件尾,x=文件尾的位置即文件长度

4.read()
  从文件读取一块,原型是int read(int handle, void*buf, unsigned len);参数buf保存读出的数据,len是读取的字节。函数返回实际读出的字节。
例:char x[200];read(hnd1,x,200);

5.write()
  写一块数据到文件中,原型是int write(int handle,void *buf, unsigned len);参数的含义同read(),返回实际写入的字节。
例:char x[]="I LoveYou";write(handle,x,strlen(x));

7.eof()
  类似feof(),测试文件是否结束,是返回1,否则返回0;原型是:inteof(int handle);
例:while(!eof(handle1)){……};

8.filelength()
  返回文件长度,原型是long filelength(int handle);相当于lseek(handle,0L,SEEK_END)
例:long x=filelength(handle);

9.rename()
  重命名文件,原型是int rename(const char*oldname, const char *newname); 参数oldname是旧文件名,newname是新文件名。成功返回0
例:rename("c:\\config.sys","c:\\config.w40");

10.chsize();
  改变文件长度,原型是int chsize(int handle, longsize);参数size表示文件新的长度,成功返回0,否则返回-1,如果指定的长度小于文件长度,则文件被截短;如果指定的长度大于文件长度,则在文件后面补''\0''。
例:chsize(handle,0x12345);
如果熟悉汇编可能会发现这种方式和汇编语言的DOS功能调用句柄式文件操作很像,比如open()就像DOS服务的3CH号功能调用,其实这种操作还有两种类型的函数就是直接用DOS功能来完成的,如_open(),_dos_open()等等。有兴趣可自已查询BCB的帮助。
  同流式文件操作相同,这种也提供了Unicode字符操作的函数,如_wopen()等等,用于9X/NT下的宽字符编程,有兴趣可自已查询BCB的帮助。
  另外,此种操作还有lock(),unlock(),locking()等用于多用户操作的函数,但在BCB中用得并不多,我就不介绍了,但如果要用C来写CGI,这些就必要的常识了,如果你有这方面的要求,那就得自已好好看帮助了.

setbuffer(设置文件流的缓冲区)
相关函数 setlinebuf,setbuf,setvbuf
表头文件 #include<stdio.h>
定义函数 void setbuffer(FILE * stream,char * buf,size_t size);
函数说明 在打开文件流后,读取内容之前,调用setbuffer()可用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址,参数size为缓冲区大小。
返回值

setlinebuf(设置文件流为线性缓冲区)
相关函数 setbuffer,setbuf,setvbuf
表头文件 #include<stdio.h>
定义函数 void setlinebuf(FILE * stream);
函数说明 setlinebuf()用来设置文件流以换行为依据的无缓冲IO。相当于调用:setvbuf(stream,(char * )NULL,_IOLBF,0);请参考setvbuf()。
返回值

setvbuf(设置文件流的缓冲区)
相关函数 setbuffer,setlinebuf,setbuf
表头文件 #include<stdio.h>
定义函数 int setvbuf(FILE * stream,char * buf,int mode,size_t size);
函数说明 在打开文件流后,读取内容之前,调用setvbuf()可以用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址,参数size为缓冲区大小,参数mode有下列几种
_IONBF 无缓冲IO
_IOLBF 以换行为依据的无缓冲IO
_IOFBF 完全无缓冲IO。如果参数buf为NULL指针,则为无缓冲IO。
返回值


上一篇:shell编程之重定向


下一篇:《HTML5多媒体应用开发》——第1章 HTML5简介1.1 HTML5是什么?