c++中文件读写中间数据以及注意

c++中文件读写中间数据以及注意

这篇文章介绍的是文件中读写数据,但特别提到的是文件中间数据的修改。

声明:你将看到如这样的代码
txt.open(“D:\line.txt”, ios_base::out |ios_base::in| ios_base::binary);
而在编译器中尝试时并未成功,失败的原因是你在没有创建这个文件时使用了ios_base::out|ios_base::in
解决方案是先用ios_base::out创建文件

这里提供另一种方案
解决方案

正片开始
先看看这个示例:

这是运行后的结果:

这是文件内容:

文件明明写进去了,而读出来的数据却并不如我们所料的那样。
虽然fstream它继承了ifstream和ofstream的特性,但指定文件读写的位置的那个"指针",它似乎不区分输入流与输入流,也就说,刚刚我们将数据写进去时,"指针"指在3的后面,也就是EOF(文件尾的标识,但似乎在这里这么表示不太合适,但为了便于理解,我还是将它引用在了这里)。接下来从文件中读取数据时,"指针"往后面的地方指去了,它似乎迷失了方向。出于这一点猜想,我在代码中
txt<<a<<b<<c;
的下面添加了
txt.seekp(0);

接下来看看运行结果:

数据确实是有了,但这里似乎还有一个问题,1,2,3,这三个数字变成了123。回顾一下之前文件中显示的,就是123!因为数字黏在一起,所以程序把他们识别成一个数了。所以,我们得做些什么:
(更改后的程序)额,图片传不了了…

:
txt.open(txt.size,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<b<<c;
txt.seekp(0);//定位至开头
txt>>linea>>lineb>>linec;

cout<<linea<<endl
       <<lineb<<endl
       <<linec<<endl;`
:
txt.open(txt.size,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<" "<<b<<" "<<c;
txt.seekp(0);//定位至开头
txt>>linea>>lineb>>linec;
cout<<linea<<endl
       <<lineb<<endl
       <<linec<<endl;

运行结果:
123

文件内容:
1 2 3

我首先使用了ios_base::trunc将文件中的原有数据清除,然后,在写入文件时,在每个数据之间加上一个空格。而这一想法来源于我曾经在进行将数据用二进制模式读写时(ios_base::binary),发现文件里的数据之间都有一个空格,起初,我猜想是’\0’(空字符,等价于NULL),后来,写入复杂的结构才发现原来是一种标识。值得一提的是,我使用的是windwos,所以我并不能保证所有系统都会这样。因此,这种方法也不能保证程序的移植性。接下来,我将对中间的数据进行更改。

:
txt.open(txt.size,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<" "<<b<<" "<<c;
txt.seekp(0);//定位至开头
txt>>linea>>lineb>>linec;

cout<<linea<<endl
       <<lineb<<endl
       <<linec<<endl;
:
txt.open(txtsize,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<b<<c;
txt.seekp(0);//定位至开头
txt<<9;

运行后的文件内容:`

923

在完成1,2,3的写入后,我直接将"指针"调到开头,写入了9,很简单,但别掉以轻心:

(更改后的程序)

txt.open(txtsize,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<b<<c;
txt.seekp(0);//定位至开头
txt<<95;

猜想一下,现在文件里面是什么样的,是9523吗?不是,其实是953,别过于惊讶,没错,机器就是这么死,但从程序的角度想一下:我只知道把东西写进去就可以了,无论它里面有没有数据。事实上,机器连这个文件上此处"指针"的位置是不是数据都不知道,所以它才能义无反顾的写下去。在平时使用记事本(txt文件)时,把鼠标向文字的中间某个地方按下,然后打字,后面的文字依然完好,这其实是txt程序里面的代码在方便着我们,我们用程序关联到一个文件,与优化这个文件的txt程序是无关的。那么,解决方法是,我们写一个具有类似功能的代码:
(全部代码,我已将txtsize所代表的文件内容改为123)

:
fstream txt;char txtsize[]="D:\\a.txt";
int a,b,c;
txt.open(txtsize,ios_base::in|ios_base::out|ios_base::trunc);//读写

txt<<a<<b<<c;
txt.seekp(0);
txt<<95;
:
fstream txt;
fstream linetxt;

char txtsize[]="D:\\a.txt";
char linetxtsize[]="D:\\linea.ttxt";
int a,b,c;

txt.open(txtsize,ios_base::in|ios_base::out);//读
linetxt.open(linetxtsize,ios_base::out|ios_trunc);//写

linetxt<<95;
txt.seekg(sizeof(char));
txt>>a;
linetxt<<a;
txt.close();
linetxt.close();

txt.open(txtsize,ios_base::out|ios_base::trunc);//写
linetxt.open(linetxtsize,ios_base::in);//读

linetxt>>a;
txt<<a;
txt.close();
linetxt.close();

此时,我使用了一个临时文件,然后在为保存9523时,先将95写入临时文件,再写入2和3,最后把临时文件里的全部写给正式文件。至于为什么是
txt.seekg(sizeof(char))
而不是
txt.seekg(sizeof(int))

因为不使用二进制模式读写文件,那么数据将以字符串形式存储,不过,这个字符串是不是以’\0’结尾,取决于实际数据,比如
txt<<6;
那么就是"6";

char a[5]=“abc”;
txt<<a;
那么就是"abc\0"。

其他
seekgseekp可以分别是使用于ifstreamofstream对象的,因为是单纯的输入与输出,所以他们有自己的文件指针,而对于fstream对象,无论是输入还是输出,都共享一个指针。因此,在使用fstream对象时使用seekg或seekp都是等价的。不过,也存在一些麻烦。

fstream txt;
txt.open("C:\\a.txt",ios::in|ios::out);//此时,共享文件指针
if(!txt.is_open())//文件异常则退出
exit(1);

在上面的代码中,程序貌似是正确的,但是当不存在a.txt时,文件会异常,而在电脑中手动创建这个文件时才可以运行成功,其原因是读写模式,而并非写模式,或者说,只有写模式(或者加些除读模式以外的)才能够创建文件。虽然fstream能够同时写和读为我们带来一些便捷。

最后
到此为止,了解了非二进制模式读写数据中一些值得注意的地方。而以二进制模式也会出现新的问题。不过,还有一个值得考虑的问题,这个问题也许在程序中用不到,但往往能增加语言的原理了解。

将一个文件以非二进制模式写入连续的(不间隔空格)的数字,使这个连续的数字超过c/c++可表示的最大数字,再读取,将会获得上面?
代码再这里
我的代码在这里了,而结果往往往往是最难预料的:
在这里插入图片描述
其原因是流被破坏。

二进制模式
需要ios::binary

此模式的要点也就是二进制中的位。

现在,来做些什么吧,期待用户输入他的名字,然后保存,再把这个数据拿出来,打印:
在这里插入图片描述
运行结果
在这里插入图片描述
出了一个问题,莫名地出现了不该有的东西,原因是读取的位置不,在read前加上:

txt.seekg(0);

现在,问题就解决了。

按理说,以什么格式写入,就要以什么格式读取,现在我以int写入,以char读取。
写入数字8256
它的二进制是
00100000 01000000
在这里插入图片描述

在这里插入图片描述
而二进制就是01000000,既然是读取一个数字的一部分,那么,再读一次,看看能不能把下一个8位读出来。
而结果就是32!

可能会有人在声明a时会这样做:
int a = 0b0010000001000000;
这是可取的,而且更直观。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值