0
点赞
收藏
分享

微信扫一扫

(P60)io流类库:文件读写,二进制文件的读写,文件随机读写tellp、tellg、seekp、seekg

龙毓七七 2023-03-07 阅读 88


文章目录

  • ​​1.文件读写​​
  • ​​2.二进制文件的读写​​
  • ​​3.文件随机读写tellp、tellg、seekp、seekg​​

1.文件读写

  • 文本读写方式1:<<, >>,
  • 文本读写方式2:get, put,
  • read,
  • write
  • 文本模式打开与二进制模式打开的区别
  • eg:P60\01.cpp

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

int main(void)
{
ofstream fout( "test.txt");
fout << "abc" << " " << 200;//先把abc 200写入到文件中
fout.close();


ifstream fin( "test.txt");
string s;
int n;
//fin>>n>>s;不按照顺序读取的话,会输出异常状态
fin >> s >> n;//用文件输入流打开文件,并将其输出
cout << s << " " << n << endl;

return 0;
}

  • 测试:
  • eg:P60\02.cpp

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

int main(void)
{
ofstream fout1( "test2.txt");
assert(fout1);
char ch;

//往一个文件中写入26个字母
for ( int i = 0; i < 26; i++)
{
ch = 'A' + i;
fout1.put(ch);
}
fout1.close();

ifstream fin1( "test2.txt");
//读取文件到结束时,文件流处于EOF状态,类型转换指针void*指针会返回空指针,就跳出循环了
while (fin1.get(ch))
{
cout << ch;
}
cout << endl;

return 0;
}

  • 测试:写入文件的结果

    26个字节
  • eg:P60\03.cpp

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

int main(void)
{
/*
如果以文本方式打开文件,写入字符的时候,遇到\n会做转换,写入\r不做转换
如果以二进制方式打开文件写入字符的时候,遇到\n不会做转换

windows平台\n会转换为 \r\n
linux平台保留不变
mac系统\n转换为\r
*/
//默认以文本方式打开文件
ofstream fout1( "test3.txt");
fout1<<"ABC\r\n";
fout1.close();
return 0;
}

  • 测试:是6个字符,A,B,C,\r,\r,\n总共6个字符
  • eg:P60\04.cpp

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

int main(void)
{
/*
(1)如果以文本方式打开文件,写入字符的时候,遇到\n会做转换,写入\r不做转换
windows平台\n会转换为 \r\n
linux平台保留不变
mac系统\n转换为\r

(2)如果以二进制方式打开文件写入字符的时候,遇到\n不会做转换

(3)以文本方式打开文件,也可以写入二进制数据
以二进制方式打开文件,也可以写入文本
写入的数据是二进制还是文本,与打开方式无关,与写入使用的函数有关
要写入二进制数据,应该用write,相应的读要用read
*/
//以二进制方式打开
ofstream fout1( "test3.txt", ios::out| ios::binary );
fout1<<"ABC\r\n";
fout1.close();
return 0;
}

  • 测试:不做任何转换,输出5个字节

2.二进制文件的读写

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

#include <cassert>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Test
{
int a;
int b;
};

//测试:以文本方式打开文件,也可以写入二进制数据
//写入的数据是二进制还是文本,与打开方式无关,与写入使用的函数有关
int main(void)
{
Test test = {100, 200};
//以文本方式打开
ofstream fout("test4.txt");
//以二进制方式写入8个字节(将100在机器中的内存表示写入文件中),转化成char*
fout.write(reinterpret_cast<char*>(&test), sizeof(Test));
fout.close();

//如何知道写入成功?可以读取出来
Test test2;
ifstream fin("test4.txt");
fin.read(reinterpret_cast<char*>(&test2), sizeof(Test));
cout<<test2.a<<" "<<test2.b<<endl;

return 0;
}

  • 测试
    因为以文本方式打开是看不到这些字符的,因为它超过了ASCII码字符所表示的范围
  • (P60)io流类库:文件读写,二进制文件的读写,文件随机读写tellp、tellg、seekp、seekg_Test


  • (P60)io流类库:文件读写,二进制文件的读写,文件随机读写tellp、tellg、seekp、seekg_ios_02

  • eg:P60\07.cpp

#include <cassert>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Test
{
int a;
int b;
};

//测试:以二进制方式打开文件,也可以写入文本
int main(void)
{
Test test = {100, 200};
//以二进制方式打开

ofstream fout("test4.txt", ios::out|ios::binary);

//c插入运算符<<是以文本方式写入数据的
//虽然以二进制方式打开,但是写入的方式是文本的方式
fout<<"abc"<<200;

return 0;
}

  • 测试:
  • (P60)io流类库:文件读写,二进制文件的读写,文件随机读写tellp、tellg、seekp、seekg_ios_03

  • P60\08.cpp

#include <cassert>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Test
{
int a;
string b;//string对象
string c;
};

//MyString类大小总是4字节,与字符串str无关
//同样string只与其成员有关,他里面的成员就是一些指针,不同平台不一样,当前平台是32字节,其他平台可能是16字节,因为持有的数据成员不同
class MyString
{
char* str;
}

int main(void)
{
Test t1;
t1.a = 100;
t1.b = "xxxabcdddddddddddddddddddddddddddddddddddddddddddddddffffffffffffffffffffffffff";
t1.c = "yyyffffffffffffffffffffffffffffffffddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";

//下面的写入方式是不行的
//因为每次写入的时候,并不是将字符串b和c的所有内容写入到文件中,总是写入了68字节而已(struct Test:4+32+32)
//只是写将string中的成员指针写进去了,而没有将指针所指向的内存写入进去
ofstream fout("test6.txt", ios::out|ios::binary);
fout.write((char*)&t1, sizeof(t1));
fout.close();

ifstream fin("test6.txt", ios::out|ios:binary);
Test t2;
fin.read((char*)&t2, sizeof(Test));
cout<<t2.a<<" "<<t2.b<<" "<<t2.c<<endl;
fin.close();

//string类型的大小总是32字节
//计算一个类型或者说一个类型所对应对象的大小,与字符串内容无关
cout<<sizeof(Test)<<endl;
string a = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
cout<<sizeof(string)<<endl;
cout<<sizeof(a)<<endl;

return 0;
}

  • 测试:
    字符串超过32字节

    写入的文件总是68字节
  • eg:P60\09.cpp

#include <cassert>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct Test
{
int a;
string b;//string对象
string c;
};

//MyString类大小总是4字节,与字符串str无关
//同样string只与其成员有关,他里面的成员就是一些指针,不同平台不一样,当前平台是32字节,其他平台可能是16字节,因为持有的数据成员不同
class MyString
{
char* str;
}

int main(void)
{
Test t1;
t1.a = 100;
t1.b = "xxxabcdddddddddddddddddddddddddddddddddddddddddddddddffffffffffffffffffffffffff";
t1.c = "yyyffffffffffffffffffffffffffffffffddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";

// //下面的写入方式是不行的
// //因为每次写入的时候,并不是将字符串b和c的所有内容写入到文件中,总是写入了68字节而已(struct Test:4+32+32)
// ofstream fout("test6.txt", ios::out|ios::binary);
// fout.write((char*)&t1, sizeof(t1));
// fout.close();

// ifstream fin("test6.txt", ios::out|ios:binary);
// Test t2;
// fin.read((char*)&t2, sizeof(Test));
// cout<<t2.a<<" "<<t2.b<<" "<<t2.c<<endl;
// fin.close();

// //string类型的大小总是32字节
// //计算一个类型或者说一个类型所对应对象的大小,与字符串内容无关
// cout<<sizeof(Test)<<endl;
// string a = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
// cout<<sizeof(string)<<endl;
// cout<<sizeof(a)<<endl;


//正确的写入方式:一个一个写入
ofstream fout("test6.txt", ios::out|ios::binary);
//写入字符串的时候,最好先写入字符串的长度,然后写入字符串实际数据
fout.write((char*)&t1.a, sizeof(int));
int len;
len = t1.b.length();
fout.write((char*)&len, sizeof(int));
fout.write((char*)&t1.b.data(), t1.b.length());

len = t1.c.length();
fout.write((char*)&len, sizeof(int));
fout.write((char*)&t1.c.data(), t1.c.length());//data()实际上调用的是c_str()方法
fout.close();


ifstream fin("test6.txt", ios::out|ios:binary);
Test t2;
fin.read((char*)&t2.a, sizeof(int));
fin.read((char*)&len, sizeof(int)); //读第二个字符串的长度
t2.b.resize(len);
fin.read((char*)&t2.b[0], len);
fin.read((char*)&len, sizeof(int));
t2.b.resize(len);
fin.read((char*)&t2.c[0], len);


cout<<t2.a<<" "<<t2.b<<" "<<t2.c<<endl;
fin.close();

return 0;
}

  • 测试:


    看乱码,首先是4个字节的整数,然后又是4个字节的整数,表示第一个字符串的长度,然后是第二个字符串的长度
  • write()成员函数

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

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

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

  • read() 成员函数

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

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

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

3.文件随机读写tellp、tellg、seekp、seekg

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

函数功能
seekp:设置输出文件流的文件流指针位置
seekg:设置输入文件流的文件流指针位置

函数原型:

ostream& seekp( streampos pos );定位到某一个位置pos,基准点是文件的开头指定的

ostream& seekp( streamoff off, ios::seek_dir dir );基准点可以是开头,结尾,或者文件当前位置,类似于Linux下的fseek,lseek

istream& seekg( streampos pos );

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

函数参数
pos:新的文件流指针位置值
off:需要偏移的值
dir:搜索的起始位置

  • 文件的随机读写tellp和tellg:获取当前文件流活动指针

输出流用tellp
输入流用tellg

函数功能
tellp:获得输出的文件流指针的当前位置,以字节为单位
tellg:获得输入的文件流指针的当前位置,以字节为单位

函数原型:
streampos tellp();
streampos tellg();

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

  • 其他

C库
fseek,ftell

Linux系统调用
lseek
lseek(fd, 0, SEEK_CUR)

seekp,seekg与C库中fseek相互对应(C库不区分输入流和输出流)
tellp,tellg与C库中ftell相互对应

seekp,seekg与Linux系统调用中lseek相互对应
Linux系统调用没有对应的tell函数,而可以通过lseek(fd, 0, SEEK_CUR)实现类似功能,其返回值为当前文件指针的位置

  • seek_dir

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

enum seek_dir {beg, cur, end};

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

  • eg:P60\10.cpp

#include <cassert>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(void)
{
ifstream fin("test7.txt");//文件输入流不会创建文件
//如果文件不存在,打开会失败
assert(fin);
fin.seekg(2);//定位到字符c

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

//输出最后一个字符
//定位到文件结尾处,向前-1

//文件流指针指向了末尾的地方
fin.seekg(-1, ios::end);
fin.get(ch);
cout<<ch<<endl;

//用以下方法可以获取文件的大小
//获取文件流指针的位置
//0是结束符的位置
fin.seekg(0, ios::end);
streampos pos = fin.tellg();
cout<<pos<<endl;

return 0;
}

  • 测试:

    当前文件大小是7个字节



举报

相关推荐

0 条评论