zoukankan      html  css  js  c++  java
  • 从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写

    一、文件的读写

    前面所提,流的读写主要有<<, >>, get, put, read, write 等操作,ofstream 继承自ostream, ifstream 继承自 istream,故操作函数都是一致的。

     C++ Code 
    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
     
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cassert>
    using  namespace std;

    int main( void)
    {
        ofstream fout( "test.txt");
        fout <<  "abc" <<  " " <<  200;
        fout.close();

        ifstream fin( "test.txt");
        string s;
         int n;
         //fin>>n>>s;
        fin >> s >> n;
        cout << s <<  " " << n << endl;

        ofstream fout1( "test2.txt");
        assert(fout1);
         char ch;

         for ( int i =  0; i <  26; i++)
        {
            ch =  'A' + i;
            fout1.put(ch);
        }
        fout1.close();

        ifstream fin1( "test2.txt");
         while (fin1.get(ch))
        {
            cout << ch;
        }
        cout << endl;


         return  0;
    }

    二、二进制文件的读写

    二进制文件不同于文本文件,它可用于任何类型的文件(包括文本文件)
    对二进制文件的读写可采用从istream类继承下来的成员函数read()和从ostream类继承下来的成员函数write()
    文件打开操作时使用枚举常量ios::binary,例如:ofstream fout(“binary.dat”,ios::out | ios::binary);


    (一)、write成员 函数

    函数功能:以字节位单位向文件流中写入整块数据,最有价值的应用可以处理结构体变量和类对象
    函数原型:

    ostream& write( const char* pch, int nCount );

    函数参数:
    pch 写入的数据的指针
    nCount 写入数据的字节大小


    (二)、read 成员 函数

    函数功能:从文件流中读出整块数据
    函数原型:

    istream& read( char* pch, int nCount ); 

    函数参数:
    pch 用来接收数据的指针
    nCount 读取的字节数的大小


     C++ Code 
    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
     
    #include <cassert>
    #include <iostream>
    #include <fstream>
    #include <string>

    using  namespace std;

    struct Test
    {
         int a;
         int b;
    };

    int main( void)
    {
        ofstream fout( "test3.txt", ios::out | ios::binary);  // 二进制方式打开,' '不做转换
        fout <<  "ABC "// << 是以文本方式写入
        fout.close();

        Test test = {  100200 };
        ofstream fout1( "test4.txt", ios::out | ios::binary);
        fout1.write( reinterpret_cast< char *>(&test),  sizeof(Test));
         // 二进制方式写入后用文本编辑器打开test4.txt 乱码
        fout1.close();

        Test test2;
        ifstream fin( "test4.txt", ios::in | ios::binary);
        fin.read( reinterpret_cast< char *>(&test2),  sizeof(Test));
        cout << test2.a <<  " " << test2.b << endl;

        ofstream fout2( "test5.txt", ios::out | ios::binary);
        fout2 <<  "abc" <<  200// << 是以文本方式写入
        fcout2.close();

         return  0;
    }

    在window下以文本方式打开文件,则写入时遇到' ' , 转换为' ',以二进制方式打开则不做转换,故test3.txt 文件大小为4个字节。

    而写入100(write 是以二进制方式写入)就不再是写入'1', '0' ,' 0' 的ascii 码,而是按照内存本来二进制形式写入,故用文本编辑器打开test4.txt 时会出现乱码。文件大小为8个字节(两个int)

    同理,test5.txt 虽然以二进制打开,但是以文本方式(<< 是以文本方式写入)写入的,故写入200后用文本编辑器打开不会出现乱码,文件大小为6个字节。

    有关文本文件与二进制文件的区别,请参考这里


    使用read, write 读取string 的时候需要注意,string 实际上内部是一些指针成员,sizeof(string)=32 (跟编译器实现有关),即string 大小是一定的,而它的指针成员保存的字符串长度不一定是32,故我们应该这些读写:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    string str1 =  "fdsfafsdsf";
    int len = str1.length();
    ofstream fout( "test6.txt", ios::out | ios::binary);
    fout.write(str1.data(), str1.length());

    string str2;
    str2.resize(len);
    ifstream fin( "test6.txt", ios::in | ios::binary);
    fin.read(&str2[ 0], len);

    如果像这样写入  fout.write((char*)&str1, sizeof(str1)); 一定是错误的,因为写入的是str1 的指针成员,而不是指针成员指向的字符串,而且str1 的大小恒等于32。


    三、文件随机读写

    (一)、当前文件流活动指针

    文件流指针用以跟踪发生 I/O 操作的位置
    每当从流中读取或写入一个字符,当前活动指针就会向前移动
    当打开方式中不含有ios::ate或ios::app选项时,则文件指针被自动移到文件的开始位置,即字节地址为0的位置。


    (二)、文件的随机读写 seekp和seekg

    seekp 和 seekg 类似与C库的fseek, linux系统调用的lseek。


    函数功能

    seekp:设置输出文件流的文件流指针位置

    seekg:设置输入文件流的文件流指针位置

    函数原型:

    ostream& seekp( streampos pos );

    ostream& seekp( streamoff off, ios::seek_dir dir );

    istream& seekg( streampos pos );

    istream& seekg( streamoff off, ios::seek_dir dir );

    函数参数

    pos:新的文件流指针位置值

    off:需要偏移的值

    dir:搜索的起始位置

    dir参数用于对文件流指针的定位操作上,代表搜索的起始位置
    在ios中定义的枚举类型:

    enum seek_dir {beg, cur, end};

    每个枚举常量的含义:
    ios::beg:文件流的起始位置
    ios::cur:文件流的当前位置
    ios::end:文件流的结束位置


    tellp 和 tellg 类似C库的ftell,,linux 系统调用的lseek(fd, 0, SEEK_CUR);

    函数功能

    tellp:获得输出的文件流指针的当前位置,以字节为单位

    tellg:获得输入的文件流指针的当前位置,以字节为单位

    函数原型:

    streampos tellp();

    streampos tellg();

    函数返回值:实际上是一个long类型


     C++ Code 
    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
     
    #include <cassert>
    #include <iostream>
    #include <fstream>
    #include <string>

    using  namespace std;


    int main( void)
    {
        ifstream fin( "test7.txt");
        assert(fin);
        fin.seekg( 2); //位置从0开始计数

         char ch;
        fin.get(ch);
        cout << ch << endl;

        fin.seekg(- 1, ios::end);  //end 实际上是EOF位置
        fin.get(ch);
        cout << ch << endl;

        fin.seekg( 0, ios::end);
        streampos pos = fin.tellg();
        cout << pos << endl;

         return  0;
    }

    假设test7.txt 现在存放abcdefg 7个字符,则输出为c g 7 .


    参考:

    C++ primer 第四版
    Effective C++ 3rd
    C++编程规范


  • 相关阅读:
    如何同步共享同一个list
    Java多线程生产者消费者模式(一)之两个线程交替执行
    Java多线程之如何在线程间共享数据
    Java多线程(四)实现多线程的三种方法之JUC的Callable接口
    Java线程的6种状态
    Java lambda表达式的进化论
    Java内部类
    Java多线程(五)锁机制之synchronized 同步方法和同步块
    Java装饰者模式
    Java多线程(三)实现多线程的三种方法之Runnable接口
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3202814.html
Copyright © 2011-2022 走看看