《好学的C++ 第2版》 第8章 文件-电子存储

主内存(RAM,随机访问内存)当计算机关闭时其数据就丢失。

对于cin和cout支持的函数调用和操作,c++提供的文件流也同样支持。前者需要#include <iostream>,后者需要#include <fstream>。流(stream)在写数据时是目的地,读数据时就是源头。

打开badgirl.txt文件:

ofstream fout("badgirl.txt"); //以独占方式打开该文件,默认文件在当前目录(运行程序的那个目录),也可给出完整路径(加上驱动器盘符也可以,这就是绝对路径,例如"c:\\badgirl.txt"就是c:\badgirl.txt文件的绝对路径)。还有ifstream、fstream

fout << "you bad but sexy girl!" << endl;

fout << "and you need bad boy!"

fout.close();

fout对象提供了一条通向磁盘文件的道路。用面向对象的术语说,fout封装了那个文件并使之具备了接收输出数据的能力。另外,虽然程序成功退出是、时C++会自动关闭仍处於打开状态的文件,但是文件不用时最好及时关闭,使程序放弃对该文件的拥有权,让其他进程可以去访问它。 //it:一个进程打开了某文件,其他进程是否可读可写该文件?试图打开该文件是否会出错?

char filename[MAX_PATH+1];

预定义常数MAX_PATH:系统所能支持的文件名(包括其路径在内)的最大长度。

若文件打开操作不成功,fout就会是NULL,可用于判断。非法路径或者像以写的方式打开只读文件都会返回NULL.

if(!fout){/*...*/}

ifstream fin;//文件以文本和输入方式打开。

fin.getline(input_line, COL_WIDTH+1);//读出一行

if(fin.eof()){/*...*/};  //到达文件末尾,fin.eof()就是true了

库函数atoi可以将字符串转为整数,这可以用来处理用户输入。

以上都是文本流,操作与控制台IO大同小异。写入文件的每一个字节都是可打印字符的ASCII编码。

二进制文件:读写这类文件时使用的都是数据的实际数值,无需进行ASCII转换(it:数字0就是写入数字0,而不是0的ASCII码值)。

####文本模式里,换行符在写时会被转换为\n\r(回车加换行wins)或\n(unix)或\r(mac)。而二进制模式里无需也不能进行此种转换。####注:回车原意是光标回到当前行的开头,换行原意是光标移动到下一行。所以不要嘲讽wins,含义上是完整的,虽然多一个字符。不过导致的问题就是跨系统的文件格式问题,产生了dos2unix这种命令。

创建文件流对象时,可将它设置为文本模式(默认)或二进制模式。前者应该使用<<、>>及getline,后者只应该使用read和write成员函数(是直接的读写操作)。

范例:(记录指的是在文件里不断重复出现的数据格式。由于数据有规律排列,通过记录号获取数据会很容易,而用结构或类来保存它们是很自然的(后续讨论)。)

#include <iostream>

#include <fstream>

using namespace std;

int get_int(int default_value);

int main(){

  char filename[MAX_PATH+1];

  int n = 0;

  char name[20];

  int age = 0;

  int recsize = sizeof(name) + sizeof(int);//计算记录的长度

  //打开文件

  cout << "Enter file name: ";

  cin.getline(filename,MAX_PATH);

  fstream fbinout(filename, ios::binary | ios::out); //ios::out是要对文件进行写操作,注意会覆盖现有文件内容,也用于打开新文件

  if(!fbinout){

  cout << "Could not open " << filename <<endl;

  system("PAUSE");

  return -1;

  }

  

  //获取要记录的数据

  cout << "Enter record number: ";

  n = get_int(0);     //获取记录号

  cout << "Enter name: "

  cin.getline(name, sizeof(name));  //获取名字

  cout << "Enter age: ";

  age = get_int(0);         //获取年龄

  

  //写入数据

  fbinout.seekp(n * recsize);   //根据记录号偏移到该记录应在的位置,否则会覆盖0号记录(it:光标或者指针默认的在最开始即0号记录处)

  fbinout.write(name, sizeof(name));

  fbinout.write((char*)(&age),sizeof(int));

  fbinout.close();

  

  system("PAUSE");

  return 0;

}

#define COL_WIDTH 80    //80是典型行宽  //it:预编译从定义处开始生效

int get_int(int default_value){

  char s[COL_WIDTH+1];

  cin.getline(s, COL_WIDTH+1);

  if (strlen(s) == 0)

    return default_value;

  return atoi(s);

}

读取数据类似,不同之处只在于:

fstream fbinin(filename, ios::binary | ios::in); //ios::in模式文件不存在会出错

fbinin.seekp(n*recsize);

fbinin.read(name, sizeof(name));

fbinin.read((char*)(&age), sizeof(int));

fbinin.close();

以下fbin将既支持读又支持写:

fstream fbin(filename, ios::binary | ios::out | ios::in);

小结捡漏:

#include <fstream>会将C++标准库提供的文件流支持功能激活(把必要的函数原型和声明引入程序)

//it:通过文件指针可实现随机访问模式(读写(包括覆盖)文件任意部分而不影响其他数据)。如果文件指针被移动到了超出文件当前长度的位置,文件会自动扩展以满足长度需要。

seekp成员函数用于移动文件指针,其入参是从文件头开始的偏移量(以字节计算)。

read和write:入参相同,都是数据地址(char*类型)和需要复制的字节数。//it:写入int要取其地址转为char*类型,但复制字节数仍是int所占用字节数(建议用sizeof获取)。

fbin.write((char*)(&x), sizeof(x));

时间: 2024-10-07 16:00:46

《好学的C++ 第2版》 第8章 文件-电子存储的相关文章

【Linux系列】【基础版】第二章 文件、目录管理

2. 文件.目录管理     2.1 有哪些文件目录         2.1.1 /bin          2.1.2 /boot         2.1.3 /dev         2.1.4 /etc         2.1.5 /home         2.1.6 /lib  /lib64         2.1.7 /meida         2.1.8 /mnt         2.1.9 /opt         2.1.10 /proc         2.1.11 /ru

Java 线程第三版 第四章 Thread Notification 读书笔记

一.等待与通知 public final void wait() throws InterruptedException 等待条件的发生. public final void wait(long timeout) throws InterruptedException 等待条件的发生.如果通知没有在timeout指定的时间内发生,它还是会返回. public final void wait(long timeout, int nanos) throws InterruptedException

C++ Primer Plus 第六版 第16章 string类和标准模板库

1.string实际上是模板具体化basic_string<char> 的一个typedef,有默认参数,所以省略了初始化参数 2.size_type是一个依赖于实现的整形 string将string::npos定义为字符串的最大长度 3.string类的构造函数P656 4.对于c-风格字符串,3种输入方法:cin>>   cin.getline(),cin.get 对于string   ,2种输入方法:cin>>,getline(cin,string对象) 5.st

Java 线程第三版 第六章 高级同步议题 读书笔记

多线程数据同步错误比较难检测,因为通常是与事件的特定发生顺序有关. 一.同步术语 Barrier(屏障) barrier是多个Thread的集合点:所有的Thread都应该到齐在这个barrier之后才能允许它们继续下去. Condition variable(条件变量) 实际上不是变量,而是与某个lock有关联的变量. Event variable(事件变量) 条件变量的另一个名称. Critical section(临界区) 临界区是synchronized方法或者block. Lock(锁

c++ primer plus(第6版)中文版 第九章编程练习答案

首先,说明下环境: linux:fedora14: IDE:eclipse: python:python2.7 python框架:django web服务器:apache web服务器的python模块:mod_wsgi 写在前面: 之前用的windows下面的xampp,写的php后台,现在想转向linux下面的python,跟以前一样,选择apache和eclipse作为自己的开发工具. eclipse的python配置, 参见之前的博客:http://blog.csdn.net/zy416

Java 线程第三版 第三章数据同步 读书笔记

多线程间共享数据问题 一.Synchronized关键字 atomic一词与"原子"无关,它曾经被认为是物质的最小的单元,不能再被拆解成更小的部分. 当一个方法被声明成synchronized,要执行此方法的thread必须先取得一个token,我们将它称为锁.一旦该方法取得(或者说是获得)锁,它将运行此方法然后释放掉(或者返回)此锁.不管方法时怎样返回的(包括通过异常)该锁会被释放. 二.Volatile关键字 如果变量被标示为volatile,每次使用该变量时都必须从主寄存器中读出

Java 线程第三版 第五章 极简同步技巧 读书笔记

一.能避免同步吗? 取得锁会因为以下原因导致成本很高: 取得由竞争的锁需要在虚拟机的层面上运行更多的程序代码. 要取得有竞争锁的线程总是必须等到锁被释放后. 1. 寄存器的效应 计算机有一定数量的主寄存器用来存储与程序有关的数据. 从逻辑上的观点来看,每个Thread都有自己的一组寄存器.当操作系统将某个Thread分配给CPU时,它会把该Thread特有的信息加载到CPU的寄存器中.在分配不同的Thread给CPU之前,它会将寄存器的信息存下来.所以Thread间绝不会共享保存在寄存器的数据.

Python核心编程(第二版) 第二章习题答案 未完待续

2-2.程序输出.阅读下面的Python脚本.#!/usr/bin/env python1 + 2 * 4(a)你认为这段脚本是用来做什么的?(b)你认为这段脚本会输出什么?(c)输入以上代码,并保存为脚本,然后运行它,它所做的与你的预期一样吗?为什么一样/不一样?(d)这段代码单独执行和在交互解释器中执行有何不同?试一下,然后写出结果.(e)如何改进这个脚本,以便它能和你想象的一样工作?答:(a)这段脚本是用来计算表达式的值(b)脚本会输出9(c)保存为脚本,运行后没有输出.和自己预期不一样.

《C++ Primer》 第四版 第7章 函数

<C++ Primer> 第四版 第7章 函数 思维导图笔记 超级具体.很具体,图片版,有利于复习查看 http://download.csdn.net/detail/onlyshi/9479711