• C C++ 文件输入与输出


     C语言:

    一 打开关闭文件

    1 fopen函数 用于打开文件

    FILE *fopen(char *filename, *type);

    fopen("c:\ccdos\clib", "rb");  如果成功的打开一个文件, fopen()函数返回文件指针,否则返回空指针(NULL)。由此可判断文件打开是否成功。

    "r" 打开文字文件只读        

    "w" 创建文字文件只写          

    "a" 增补,如果文件不存在则创建一个

    "r+" 打开一个文字文件读/写

    "w+" 创建一个文字文件读/写

    "a+" 打开或创建一个文件增补

    "b" 二进制文件(可以和上面每一项合用)

    "t" 文这文件(默认项)

    2. fclose()函数
    fclose()函数用来关闭一个由fopen()函数打开的文件,其调用格式为:

    int fclose(FILE *stream);该函数返回一个整型数。当文件关闭成功时,返回0,否则返回一个非零值。可以根据函数的返回值判断文件是否关闭成功。

    二 有关文件操作的函数

    本节所涉及到的文件读写函数均是指顺序读写,即读写了一条信息后,指针自动加1.

    下面分别介绍写操作函数和读操作函数。   

    1. 文件的顺序写函数

    fprintf()、fputs()和fputc()函数均为文件的顺序写操作函数,其调用格式如下:

    int fprintf(FILE *stream, char *format, <variable-list>);

    int fputs(char *string, FILE *steam);

    int fputc(int  ch, FILE *steam); 上述三个函数的返回值均为整型量。

    fprintf() 函数的返回值为实际写入文件中的字符个数(字节数)。如果写错误,则返回一个负数;

    fputs()函数返回0时表明将string指针所指的字符串写入文件中的操作成功, 返回非0时,表明写操作失败。

    fputc()函数返回一个向文件所写字符的值,此时写操作成功,否则返回EOF(文件结束结束其值为-1, 在stdio.h中定义)表示写操作错误。  

    fprintf( ) 函数中格式化的规定与printf( ) 函数相同,所不同的只是fprintf()函数是向文件中写入。而printf()是向屏幕输出。

    例如:

    fputs("Your score of TOEFLis", fp);/*向所建文件写入一串字符*/
    fputc(':', fp);    /*向所建文件写冒号:*/
    fprintf(fp, "%d ", i); /*向所建文件写一整型数*/
    fprintf(fp, "%s", s);  /*向所建文件写一字符串*/

    2. 文件的顺序读操作函数

      函数fscanf()、fgets()和fgetc()均为文件的顺序读操作函数,其调用格式如下:

    int fscanf(FILE *stream, char *format, <address-list>);      

    char fgets(char *string, int n, FILE *steam);

    int fgetc(FILE *steam);      

    fscanf()函数的用法与scanf()函数相似,只是它是从文件中读到信息。 fscanf()函数的返回值为EOF(即-1), 表明读错误,否则读数据成功。读到空白字符自动返回。

    fgets()函数从文件中读取至多n-1个字符(n用来指定字符数), 并把它们放入string指向的字符串中,在读入之后自动向字符串未尾加一个空字符,读成功返回string指针,失败返回一个空指针。

    fgetc()函数返回文件当前位置的一个字符,读错误时返回EOF。

    3. 文件的随机读写

    有时用户想直接读取文件中间某处的信息, 若用文件的顺序读写必须从文件 头开始直到要求的文件位置再读, 这显然不方便。Turbo C2.0提供了一组文件的 随机读写函数, 即可以将文件位置指针定位在所要求读写的地方直接读写。

    文件的随机读写函数如下:

    int fseek (FILE *stream, long offset, int fromwhere);

    int fread(void *buf, int size, int count, FILE *stream);

    int fwrite(void *buf, int size, int count, FILE *stream);

    long ftell(FILE *stream);

    fseek()函数的作用是将文件的位置指针设置到从fromwhere开始的第offset 字节的位置上, 其中fromwhere是下列几个宏定义之一:

    文件位置指针起始计算位置fromwhere

    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    符号常数 数值 含义

    ───────────────────────────

    SEEK_SET 0 从文件开头

    SEEK_CUR 1 从文件指针的现行位置

    SEEK_END 2 从文件末尾

    ━━━━━━━━━━━━━━━━━━━━━━━━━━━

    offset是指文件位置指针从指定开始位置(fromwhere指出的位置)跳过的字节数。它是一个长整型量, 以支持大于64K字节的文件。

    fseek()函数一般用于对 二进制文件进行操作。当fseek()函数返回0时表明操作成功, 返回非0表示失败。

    fread()函数是从文件中读count个字段, 每个字段长度为size个字节, 并把 它们存放到buf指针所指的缓冲器中。

    fwrite()函数是把buf指针所指的缓冲器中, 长度为size个字节的count个字 段写到stream指向的文件中去。

    随着读和写字节数的增大, 文件位置指示器也增大, 读多少个字节, 文件位 置指示器相应也跳过多少个字节。读写完毕函数返回所读和所写的字段个数。

    ftell()函数返回文件位置指示器的当前值,这个值是指示器从文件头开始 算起的字节数, 返回的数为长整型数, 当返回-1时, 表明出现错误。

    下面程序把一个浮点数组以二进制方式写入文件test_b.dat中。

    例14:

    #include <stdio.h>

    main()

    {

    float f[6]={3.2, -4.34, 25.04, 0.1, 50.56, 80.5};

    /*定义浮点数组并初始化*/

    int i;

    FILE *fp;

    fp=fopen("test_b.dat", "wb"); /*创建一个二进制文件只写*/

    fwrite(f, sizeof(float), 6, fp);/*将6个浮点数写入文件中*/

    fclose(fp); /*关闭文件*/

    }

    下面例子从test_b.dat文件中读100个整型数, 并把它们放到dat数组中。 例15:

    #include <stdio.h>

    main()

    {

    FILE *fp;

    intdat[100];

    fp=fopen("test_b.dat", "rb");/*打开一个二进制文件只读*/

    if(fread(dat, sizeof(int), 100, fp)!=100)

    /*判断是否读了100个数*/

    {

    if(feof(fp))

    printf("End of file"); /*不到100个数文件结束*/

    else

    printf("Read error"); /*读数错误*/

    fclose(fp); /*关闭文件*/

    }

    注意:

    当用标准文件函数对文件进行读写操作时, 首先将所读写的内容放进缓冲区, 即写函数只对输出缓冲区进行操作, 读函数只对输入缓冲区进行操作。例如向一 个文件写入内容, 所写的内容将首先放在输出缓冲区中, 直到输出缓冲区存满或使用fclose()函数关闭文件时, 缓冲区的内容才会写入文件中。若无fclose()函数, 则不会向文件中存入所写的内容或写入的文件内容不全。有一个对缓冲区 进行刷新的函数, 即fflush(), 其调用格式为:

    int fflush(FILE *stream);该函数将输出缓冲区的内容实际写入文件中, 而将输入缓冲区的内容清除掉。

    4. feof()和rewind()函数

    这两个函数的调用格式为:

    int feof(FILE *stream);

    int rewind(FILE *stream);

    feof()函数检测文件位置指示器是否到达了文件结尾,若是则返回一个非0值, 否则返回0。这个函数对二进制文件操作特别有用, 因为二进制文件中,文件结尾标志EOF也是一个合法的二进制数,只简单的检查读入字符的值来判断文件是否结束是不行的。如果那样的话, 可能会造成文件未结尾而被认为结尾, 所以就必须有feof()函数。

    下面的这条语句是常用的判断文件是否结束的方法。

    while(!feof(fp))

    fgetc(fp);

    rewind()函数用于把文件位置指示器移到文件的起点处, 成功时返回0,否则, 返回非0值。

    C语言本身并不提供输入输出语句,输入和输出操作是由函数来实现的。在C标准函数库中提供了一些输入输出函数,例如,printf函数和scanf函数。

    基于C++的文件操作

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

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

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

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

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

    void open(const char* filename,int openmode,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<<<123;要把3.1415926以5位精度输出:file1<<<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=' ');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符' '。例如:

    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);//把文件的读指针从当前位置向后移1234个字节 file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节

    -------------------------------------------------------------------------------------------------------------------------------------------------------------

    文本文件读写:

    #include <fstream>
    #include <iostream>
    using namespace std;
    
    
    int main()
    {
        //文本文件打开方式设为可读写
    //     fstream outfile("f1.dat",ios::out|ios::in);
    //     if (!outfile)
    //     {
    //         cout<<"open error!"<<endl;
    //          exit(1);
    // }

    // char a[10]; // cout<<"输入十个数字"<<endl; // //写入文件中 // for (int i=0;i<10;i++) // { // cin>>a[i]; // outfile<<a[i]<<' '; // } // //从文件读取 // for (int i=0;i<10;i++) // { // outfile>>a[i]; // cout<<a[i]<<' '; // } // outfile.close(); //从键盘读入一行字符,将其中的字母存在磁盘文件 // ofstream outfile("f2.dat"); // if (!outfile) // { // cout<<"open error"<<endl; //   exit(1);
    // } // char c[80]; // cin.getline(c,80);//最多提取80个字符,或者遇到默认终止符 结束 // for (int i=0;c[i]!='';i++) // { // if (c[i]>=65&&c[i]<=90||c[i]>=97&&c[i]<=122) // { // //outfile.put(c[i]);或者 // outfile<<c[i]; // cout<<c[i]; // } // } // cout<<endl; // outfile.close(); //从上面的文件读入字符,将其中的小写字母改写为大写字母在存在f3文件 ifstream infile("f2.dat"); if (!infile) { cout<<"openerrr";   exit(1);
    } ofstream outfile3(
    "f3.dat"); if (!outfile3) { cout<<"error";   exit(1);
    }
    char ch; while (infile>>ch/*infile.get(ch)*/) { if (ch>=97&&ch<=122) { ch=ch-32; } outfile3<<ch; cout<<ch; } cout<<endl; infile.close(); outfile3.close(); return 0; }

    二进制文件读写:

    主要用istream类的成员函数read 和write来实现 ,成员函数原型:

    istream& read(char *buffer,int len);

    ostream& write(const char *buffer,int len);

    字符指针指向内存中一段存储空间,len是读写的字节数。

    #include <fstream>
    #include <iostream>
    using namespace std;
    struct student 
    {
        char name[20];
        int num;
        int age;
        char sex;
    };
    int main()
    {
        student stu[3]={"Li",1001,18,'f',"Fun",1002,19,'f',"Wa",1003,17,'m'};
        ofstream outfile("student.dat",ios::binary);//和文件后缀名没关系,即使写成student.txt还是打开乱码,因为编码是自定义的,默认的字符编码解释不了的。
        if (!outfile)
        {
            cerr<<"open erroe";
            exit(1);
        }
    //     for (int i=0;i<3;i++)
    //     {
    //         //outfile.write((char *)&stu[i],sizeof(stu[i]));
    //         outfile.write((char *)(stu+i),sizeof(stu[i]));
    //     }
        //取代for循环,直接一句话
        outfile.write((char *)stu,sizeof(stu));
        outfile.close();
    
        
        //读取
        ifstream infile("student.dat",ios::binary);
        if (!infile)
        {
            cerr<<"open error";
            exit(1);
        }
         student stu2[3];
         infile.read((char*)stu2,sizeof(stu2));
        infile.close();
    
        //打印
        for (int i=0;i<3;i++)
        {
            cout<<stu2[i].name<<endl;
            cout<<stu2[i].age<<endl;
            cout<<stu2[i].num<<endl;
            cout<<stu2[i].sex<<endl;
    
        }
        return 0;
        
    }

    注意

    fstream iofile("student.dat",ios::in|ios::out|ios::binary);

    if(!iofile)

    {cout<<"open error";

    exit(1);} //不知道为何新建一个能输入输出的二进制文件总会出错,二上面例子中新建一个输入输出的文本文件可以。

    随机访问二进制数据文件

    利用seekg(),seekp等成员函数移动指针,随机的访问文件中任意位置上的数据。

    举例:(文件读写有两个指针,读文件指针和写指针。)

    iofile.seekg(2*sizeof(stu[2]),ios::beg);把输入指针移动到第三个学生数据开头

    iofile.read((char *)&stu2[0],sizeof(stu2[0]));

    iofile.seekp(2*sizeof(stu[2]),ios::beg);把输出指针移动到第三个学生数据开头

    iofile.write((char *)&stu2[0],sizeof(stu2[0]));

  • 相关阅读:
    JS实现继承的几种方式
    跨平台APP----对Cordova,APPCan,DCloud,APICloud四大平台的分析
    cordova生成的android项目导入到Android studio 2.X 中遇到的问题解决方案
    链操作相关命令(包括启动,重启,删除)
    冷钱包和热钱包有什么区别?
    常用命令之git/linux
    centos安装git,go,shasum,okexchain环境
    iterm2的下载安装与配置
    使用jsdoc-to-markdown提前js文件的文档
    基于sphinx的文档(一)将md转为rst
  • 原文地址:https://www.cnblogs.com/Yogurshine/p/3677201.html
Copyright © 2020-2023  润新知