C++ primer plus 第17 章 输入、输出和文件:文件输入和输出03:文件模式:二进制文件
系列文章目录
17.4.5 文件模式
程序清单17.18 append.cpp
程序清单17.19 binary.cpp
文章目录
- 系列文章目录
- 17.4.5 文件模式
- 程序清单17.18 append.cpp
- 程序清单17.19 binary.cpp
- 17.4.5 文件模式
- 1.追加文件来看一个在文件尾追加数据的程序。
- 程序清单17.18 append.cpp
- 2.二进制文件
- 二进制文件和文本文件
- 程序清单17.19 binary.cpp
17.4.5 文件模式
文件模式描述的是文件将被如何使用:读、写、追加等。将流与文件关联时(无论是使用文件名初始化文件流对象,还是使用open()方法),都可以提供指定文件模式的第二个参数:
ifstream fin("banjo",model);/constructor with mode arqument
ofstream fout();
fout.open("harp",mode2);//open()with mode arguments
ios base 类定义了一个 openmode 类型,用于表示模式;与 fimtflags 和 iostate 类型一样,它也是一种bitmask 类型(以前,其类型为 int)。可以选择 ios base 类中定义的多个常量来指定模式,表 17.7列出了这些常量及其含义。C++文件 I/O作了一些改动,以便与 ANSIC 文件 I/O 兼容。
如果 ifstream 和 ofstream 构造函数以及 open( )方法都接受两个参数,为什么前面的例子只使用一个参数就可以调用它们呢?您可能猜到了,这些类成员函数的原型为第二个参数(文件模式参数)提供了默认值。例如,ifstream open()方法和构造函数用ios base:in(打开文件以读取)作为模式参数的默认值,而ofstream open()方法和构造函数用ios base:out|ios base:trunc(打开文件,以读取并截短文件)作为默认值。位运算符 OR(1)用于将两个位值合并成一个可用于设置两个位的值。fstream 类不提供默认的模式值,因此在创建这种类的对象时,必须显式地提供模式。
注意,ios base::trunc标记意味着打开已有的文件,以接收程序输出时将被截短;也就是说,其以前的内容将被删除。虽然这种行为极大地降低了耗尽磁盘空间的危险,但您也许能够想象到这样的情形,即不希望打开文件时将其内容删除。当然,C++提供了其他的选择。例如,如果要保留文件内容,并在文件尾添加(追加)新信息,则可以使用ios base::app 模式:
ofstream fout("bagels",ios base::outios | base::app);
上述代码也使用|运算符来合并模式,因此ios base::out|ios base::app意味着启用模式out和 app(参见图 17.6)。
老式C++实现之间可能有一些差异。例如,有些实现允许省略前一例子中的iosbase::out,有些则不允许。如果不使用默认模式,则最安全的方法是显式地提供所有的模式元素。有些编译器不支持表17.6中的所有选项,有些则提供了表中没有列出的其他选项。这些差异导致的后果之一是,可能必须对后面的例子作一些修改,使之能够在所用的系统中运行。好在C++标准提供了更高的统一性。
标准 C++根据 ANSIC标准 IO 定义了部分文件 JO。实现像下面这样的 C++语句时:
ifstream fin(filename, c++mode);
就像它使用了C的fopen()函数一样:
fopen(filename, cmode);
其中,c++mode 是一个 openmode 值,如 ios base::in;而 cmode 是相应的℃模式字符串,如“r”表 17.8列出了 C++模式和C模式的对应关系。注意,ios base::out本身将导致文件被截短,但与ios base::in起使用时,不会导致文件被截短。没有列出的组合,如ios base:in[vn]ios base::trunc,将禁止文件被打开。is open()方法用于检测这种故障。
注意,ios_base:ate 和ios_base::app 都将文件指针指向打开的文件尾。二者的区别在于,ios base::app模式只允许将数据添加到文件尾,而iosbase::ate模式将指针放到文件尾。显然,各种模式的组合很多,我们将介绍几种有代表性的组合。
1.追加文件来看一个在文件尾追加数据的程序。
该程序维护一个存储来客清单的文件。该程序首先显示文件当前的内容(如果有话)。在尝试打开文件后,它使用isopen()方法来检查该文件是否存在。接下来,程序以ios_base:app 模式打开文件,进行输出。然后,它请求用户从键盘输入,并将其添加到文件中。最后,程序显示修订后的文件内容。程序清单17.18演示了如何实现这些目标。请注意程序是如何使用isopen()方法来检测文件是否被成功打开的。
注意:在早期,文件 I/0 可能是 C++最不标准的部分,很多老式编译器都不遵守当前的标准。例如,有些编译器使用诸如 nocreate 等模式,而这些模式不是当前标准的组成部分。另外,只有一部分编译器要求在第二次打开同一个文件进行读取之前调用fin.clear()。
程序清单17.18 append.cpp
// append.cpp -- appending information to a file
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib> // (or stdlib.h) for exit()const char * file = "guests.txt";
int main()
{using namespace std;char ch;// show initial contentsifstream fin;fin.open(file);if (fin.is_open()){cout << "Here are the current contents of the "<< file << " file:\n";while (fin.get(ch))cout << ch;fin.close();}// add new namesofstream fout(file, ios::out | ios::app);if (!fout.is_open()){cerr << "Can't open " << file << " file for output.\n";exit(EXIT_FAILURE);}cout << "Enter guest names (enter a blank line to quit):\n";string name;while (getline(cin,name) && name.size() > 0){fout << name << endl;}fout.close();// show revised filefin.clear(); // not necessary for some compilersfin.open(file);if (fin.is_open()){cout << "Here are the new contents of the "<< file << " file:\n";while (fin.get(ch))cout << ch;fin.close();}cout << "Done.\n";// cin.get();return 0;
}
此时,guests.txt文件还没有创建,因此程序不能预览该文件。但第二次运行该程序时,guests.txt文件已经存在,因此程序将预览该文件。另外,新数据被追加到旧文件的后面,而不是取代它们。
可以用任何文本编辑器来读取 guest.txt的内容,包括用来编写源代码的编辑器。
2.二进制文件
将数据存储在文件中时,可以将其存储为文本格式或二进制格式。文本格式指的是将所有内容(甚至数字)都存储为文本。例如,以文本格式存储值-2.324216e+07时,将存储该数字包含的13个字符。这需要将浮点数的计算机内部表示转换为字符格式,这正是<<插入运算符完成的工作。另一方面,二进制格式指的是存储值的计算机内部表示。也就是说,计算机不是存储字符,而是存储这个值的 64位 double 表示。对于字符来说,二进制表示与文本表示是一样的,即字符的 ASCI 码的二进制表示。对于数字来说,二进制表示与文本表示有很大的差别(参见图17.7)。
每种格式都有自己的优点。文本格式便于读取,可以使用编辑器或字处理器来读取和编辑文本文件,可以很方便地将文本文件从一个计算机系统传输到另一个计算机系统。二进制格式对于数字来说比较精确,因为它存储的是值的内部表示,因此不会有转换误差或舍入误差。以二进制格式保存数据的速度更快,因为不需要转换,并可以大块地存储数据。二进制格式通常占用的空间较小,这取决于数据的特征。然而,如果另一个系统使用另一种内部表示,则可能无法将数据传输给该系统。同一系统上不同的编译器也可能使用不同的内部结构布局表示。在这种情况下,则必须编写一个将一种数据转换成另一种的程序。来看一个更具体的例子。考虑下面的结构定义和声明:
const int LIM=20;
struct planet
{char name[LIM];// name of planetdouble population;// its populationdouble g;// its acceleration of qravity
}
planet pl;
要将结构p的内容以文本格式保存,可以这样做:
ofstream fout("planets.dat",ios base::outios |base::app) ;
fout << pl.name<<""<< pl.population << " "<< pl.g << "\n"
必须使用成员运算符显式地提供每个结构成员,还必须将相邻的数据分隔开,以便区分。如果结构有30个成员,则这项工作将很乏味。
要用二进制格式存储相同的信息,可以这样做:
ofstream fout("planets.dat"ios base::outios base::appios|base::binary);
fout.write((char *)&pl,sizeof pl);
上述代码使用计算机的内部数据表示,将整个结构作为一个整体保存。不能将该文件作为文本读取,但与文本相比,信息的保存更为紧凑、精确。它确实更便于键入代码。这种方法做了两个修改:
使用二进制文件模式:
使用成员函数write()。
下面更详细的介绍这两项修改。
有些系统(如Windows)支持两种文件格式:文本格式和二进制格式。如果要用二进制格式保存数据应使用二进制文件格式。在C++中,可以将文件模式设置为ios base::binary 常量来完成。要知道为什么在Windows系统上需要完成这样的任务,请参见后面的旁注“二进制文件和文本文件”。
二进制文件和文本文件
使用二进制文件模式时,程序将数据从内存传输给文件(反之亦然)时,将不会发生任何隐藏的转换而默认的文本模式并非如此。例如,对于 Windows文本文件,它们使用两个字符的组合(回车和换行)表示换行符;Macintosh 文本文件使用回车来表示换行符;而 UNIX和 Linux 文件使用换行(linefeed)来表示换行符。C++是从 UNIX系统上发展而来的,因此也使用换行(linefecd)来表示换行符。为增加可移植性,Windows C++程序在写文本模式文件时,自动将C++换行符转换为回车和换行;Macintosh C++程序在写文件时,将换行符转换为回车。在读取文本文件时,这些程序将本地换行符转换为C++格式。对于二进制数据,文本格式会引起问题,因此 double 值中间的字节可能与换行符的 ASCII 码有相同的位模式。另外在文件尾的检测方式也有区别。因此以二进制格式保存数据时,应使用二进制文件模式(UNIX 系统只有一种文件模式,因此对于它来说,二进制模式和文本模式是一样的)。
要以二进制格式(而不是文本格式)存储数据,可以使用write0)成员函数。前面说过,这种方法将内存中指定数目的字节复制到文件中。本章前面用它复制过文本,但它只逐字节地复制数据,而不进行任何转换。例如,如果将一个long 变量的地址传递给它,并命令它复制4个字节,它将复制 long值中的4个字节,而不会将它转换为文本。唯一不方便的地方是,必须将地址强制转换为指向char 的指针。也可以用同样的方式来复制整个planet结构。要获得字节数,可以使用sizeof运算符:
fout.write((char *)&pl,sizeof pl);
这条语句导致程序前往 pl结构的地址,并将开始的36个字节(sizeofpl表达式的值)复制到与 fout相关联的文件中。
要使用文件恢复信息,请通过一个ifstream对象使用相应的read()方法:
ifstream fin("planets.dat",ios base::in | ios base::binary);
fin.read((char *)&pl,sizeof pl);
这将从文件中复制 sizeofpl个字节到p1结构中。同样的方法也适用于不使用虚函数的类。在这种情况下,只有数据成员被保存,而方法不会被保存。如果类有虚方法,则也将复制隐藏指针(该指针指向虚函数的指针表)。由于下一次运行程序时,虚函数表可能在不同的位置,因此将文件中的旧指针信息复制到对象中,将可能造成混乱(请参见“编程练习6”中的注意)。
提示:read()和 write()成员函数的功能是相反的。请用read()来恢复用 write()写入的数据
程序清单17.19使用这些方法来创建和读取二进制文件。从形式上看,该程序与程序清单17.18相似,但它使用的是 write()和read(),而不是插入运算符和 get()方法。另外,它还使用控制符来格式化屏幕输出。注意:虽然二进制文件概念是 ANSIC的组成部分,但一些C和C++实现并没有提供对二进制文件模式的支持。原因在于:有些系统只有一种文件类型,因此可以将二进制操作(如read()和 write())用于标准文件格式。因此,如果实现认为 ios base:binary 是非法常量,只要删除它即可。如果实现不支持 fixed和 right 控制符,则可以使用 cout.setf(ios base::fixed、ios base::foatfield)和 cout.setf(ios base:.right.ios base::adiustfield)。另外,也可能必须用ios替换ios base。其他编译器(特别是老式编译器)可能还有其他特征。
程序清单17.19 binary.cpp
// binary.cpp -- binary file I/O
#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // (or stdlib.h) for exit()inline void eatline() { while (std::cin.get() != '\n') continue; }
struct planet
{char name[20]; // name of planetdouble population; // its populationdouble g; // its acceleration of gravity
};const char * file = "planets.dat";int main()
{using namespace std;planet pl;cout << fixed << right;// show initial contentsifstream fin;fin.open(file, ios_base::in |ios_base::binary); // binary file//NOTE: some systems don't accept the ios_base::binary modeif (fin.is_open()){cout << "Here are the current contents of the "<< file << " file:\n";while (fin.read((char *) &pl, sizeof pl)){cout << setw(20) << pl.name << ": "<< setprecision(0) << setw(12) << pl.population<< setprecision(2) << setw(6) << pl.g << endl;} fin.close();}// add new dataofstream fout(file, ios_base::out | ios_base::app | ios_base::binary);//NOTE: some systems don't accept the ios::binary modeif (!fout.is_open()){cerr << "Can't open " << file << " file for output:\n";exit(EXIT_FAILURE);}cout << "Enter planet name (enter a blank line to quit):\n";cin.get(pl.name, 20);while (pl.name[0] != '\0'){eatline();cout << "Enter planetary population: ";cin >> pl.population;cout << "Enter planet's acceleration of gravity: ";cin >> pl.g;eatline();fout.write((char *) &pl, sizeof pl);cout << "Enter planet name (enter a blank line ""to quit):\n";cin.get(pl.name, 20);}fout.close();// show revised filefin.clear(); // not required for some implementations, but won't hurtfin.open(file, ios_base::in | ios_base::binary);if (fin.is_open()){cout << "Here are the new contents of the "<< file << " file:\n";while (fin.read((char *) &pl, sizeof pl)){cout << setw(20) << pl.name << ": "<< setprecision(0) << setw(12) << pl.population<< setprecision(2) << setw(6) << pl.g << endl;}fin.close();}cout << "Done.\n";
// keeping output window open// cin.clear();// eatline();// cin.get();return 0;
}
看到该程序的主要特征后,下面再次讨论前面提到的几点。程序在读取行星的g值后,将使用下面的代码(以内嵌eatline()函数的形式):
while(std::cin.get()!=n')continue;
这将读取并丢弃输入中换行符之前的内容。考虑循环中的下一条输入语句:
cin.get(pl.name,20);
如果保留换行符,该语句将换行符作为空行读取,然后终止循环,
您可能会问,如果该程序是否可以使用string对象而不是字符数组来表示planet 结构的name 成员?答案是否定的,至少在不对设计做重大修改的情况下是否定的。问题在于,string对象本身实际上并没有包含字符串,而是包含一个指向其中存储了字符串的内存单元的指针。因此,将结构复制到文件中时,复制的将不是字符串数据,而是字符串的存储地址。当您再次运行该程序时,该地址将毫无意义。
相关文章:

C++ primer plus 第17 章 输入、输出和文件:文件输入和输出03:文件模式:二进制文件
系列文章目录 17.4.5 文件模式 程序清单17.18 append.cpp 程序清单17.19 binary.cpp 文章目录 系列文章目录17.4.5 文件模式程序清单17.18 append.cpp程序清单17.19 binary.cpp17.4.5 文件模式1.追加文件来看一个在文件尾追加数据的程序。程序清单17.18 append.cpp2.二进制文…...

网络安全之sql靶场(11-23)
sql靶场(11-23) 目录 第十一关(post注入) 第十二关 第十三关 第十四关 第十五关 第十六关 第十七关 第十八关 第十九关 第二十关 第二十一关 第二十二关 第二十三关 第十一关(post注入) 查看…...

WordPress网站被入侵,劫持收录事件分析
7.15,网站被入侵,但是直到7月17日,我才发现被入侵。 16日,17日正常更新文章,17日查询网站收录数据时,在站长资源平台【流量与关键词】查询上,我发现了比较奇怪的关键词。 乱码关键词排名 起初…...

原生js: 实现三个水平tab按钮, 默认第一个上面有class, 点击另外的实现class=‘cur‘的切换的效果
问: <ul><li class"cur">热门问题</li><li>订阅问题</li><li>使用问题</li></ul> 这是我的代码, 这是我的代码: // 遍历 helpInfoClass 数组helpInfoClass.forEach((item, index) > {var itemId item[0];var i…...

C#语言基础速成Day07
“知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得。” 目录 前言文章有误敬请斧正 不胜感恩!||Day07 C#常见数据结构:1. 集合(Collection)1.1 **List<T>**1.2 **H…...

jvm运行时常量池溢出的原因
Java虚拟机(JVM)的运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存储类和接口的常量池表,包括字面量和对类型、字段和方法的符号引用。运行时常量池溢出通常指的是常量池的内存使用达到了JVM设…...
floyd算法详解
算法是一种用于求解所有顶点对之间的最短路径问题的算法,特别适用于稠密图。下面是一个使用C实现的算法示例: #include <iostream> #include <climits> // For INT_MAXusing namespace std;const int V 4; // 图的顶点数// 定义一个函数来…...

Web前端性能优化的方向
减少dom渲染复杂列表优化缓存优化首页背景图片加载慢,可以放在服务器上,读取绝对路径900k的图片大小有些大,可以对图片进行压缩,tinypng网站压缩、熊猫压缩、bing域名下的图片url后面带参数w、h、qlt剪裁下拉框数据较多进行懒加载…...

【面试题】设计模式-责任链模式
设计模式-责任链模式 前言责任链简历案例代码小结 前言 我们知道,设计模式是面试时经常被问到的问题之一,这是因为设计模式能够体现出代码设计的美感,且在很多框架的底层也都会使用到各种设计模式,所以对设计模式的考察ÿ…...

JavaEE 第8节 单例模式详解
目录 概念 饿汉模式 懒汉模式 懒汉模式在多线程环境下的优化 1.线程安全问题 2.效率问题 3.指令重排序导致的问题 1)为什么要进行指令重排序? 2)指令重排序在上述代码为什么会构成问题? 导读: 单例模式是一种…...

OpenAI 发布 GPT-4o 模型安全评估报告:风险等级为“中等”|TodayAI
OpenAI 近日发布了最新的 GPT-4o 系统卡,这是一份研究文件,详细介绍了公司在推出其最新 AI 模型之前所进行的安全措施和风险评估。根据该评估报告,GPT-4o 的总体风险等级被评定为 “中等” 。 GPT-4o 于今年 5 月首次公开发布。在其发布之前…...

学习前端面试知识
2024-8-9 打卡第十天 学习视频链接 js延迟加载 延迟加载:等页面加载完成后再进行加载提高页面加载速度defer属性,同步加载,让脚本与文档同步解析,顺序执行,当文档解析完成再执行defer,执行完再执行脚本&…...

Leetcode JAVA刷刷站(9)回文数
一、题目概述 二、思路方向 在Java中,判断一个整数是否为回文数,可以通过将该整数转换为字符串,然后比较字符串与其反转后的字符串是否相同来实现。但这种方法在整数非常大时可能不太高效,因为它依赖于字符串操作。一个更高效的方…...

数据结构算法
⩕ 单调栈 1、概念 对于一个栈,维持其单调性,有两种情况,单调递增栈:由栈底到栈顶单调递增 单调递减栈:由栈底到栈顶单调递减 2、核心模板( 单调递增栈 ) stack<int> stk; void …...

WordPress个性化站点
这个信息爆炸的时代,拥有一个能够迅速传达信息、展示个性、并能够与世界互动的在线平台,已成为企业和个人的基本需求。WordPress以其无与伦比的易用性和强大的扩展性,成为了构建此类平台的首选工具。而LNMP是由Linux、Nginx、MySQL和PHP组成的…...

GESP C++ 2024年03月一级真题卷
一、单选题(每题 2 分,共 30 分) 第 1 题 C表达式 (3 - 2) * 3 5 的值是( )。 A. -13 B. 8 C. 2 D. 0 答案:B 解析:略 第 2 题 C 语句 cout << "5%2" << 5 % 2 执行后的输出是…...

Linux驱动开发基础(Hello驱动)
所学内容来自百问网 目录 1. 文件在内核中的表示 2. 打开字符设备节点时,内核中也有对应的struct file 3. 编写驱动程序步骤 4. 相关知识点 4.1 涉及函数解析 4.2 module_init/module_exit的实现 4.3 register_chrdev的内部实现 4.4 class_destroy/device_…...

centos7安装 ES集群 elasticsearch
这里写自定义目录标题 编写启动脚本 elasticsearch.sh启动可能报错:elasticsearch 7.10启动报错 bootstrap checks failed解决方法问题原因:注意 退出xshell,重新登录: 上面两个配置项改完后,ES启动用户(es 或root) **…...

互联网应用主流框架整合【Redis数据结构及常用命令】
在大部分情况下我们使用Redis只是执行一些简单的命令操作,通常无需区分是否是在一个连接池里的同一个链接去执行,如果需要执行多条命令,需要保证命令在同一个链接里完成,则采用SessionCallback接口操作即可 Redis数据结构-字符串…...

GORM 自动迁移与命名策略
在现代软件开发中,数据库结构的维护和迁移是常见的挑战之一。GORM,作为 Go 语言中强大的 ORM 库,提供了自动迁移功能,帮助开发者轻松地管理数据库表结构的变更。此外,GORM 还允许开发者通过命名策略(Naming…...

python社会科学问题研究的计算实验
实验十五:社会科学问题研究的计算实践 1.实验目标及要求 (1)掌握网络视角 (2)掌握社会网络基础内容 (3)掌握友谊悖论 2.实验主要内容 随机生成一次符合社会网络特征的网络,通过计…...

Element Plus 发布 2.8.0
功能特性 组件更新 [color-picker] alpha-slider a11y (#14245 by tolking)添加 mention 组件 (#17586 by Fuphoenixes)[tree-v2] 添加 scrollTo 方法 (#14050 by kaine0923)[drawer] 添加 append-to 属性 (#17761 by tolking)[table] tree children 添加严格检查 (#13519 by t…...

解释区块链技术的应用场景和优势-水文
区块链技术是一种去中心化的分布式账本技术,其应用场景和优势如下: 金融领域:区块链可以用于加密货币交易,提供安全的、去中心化的支付系统。它也可以用于股票、债券和其他金融交易的记录和结算,提高交易的透明度和效率…...

等保测评基础知识(一)
1、时间类: 网络安全法: 2017年6月1日等保2.0实施时间: 2019年12月1日密码法: 2020年1月1日个人信息保护法: 2021年11月1日,数据安全法实施时间: 2021年9月1日关键信息基础…...

股指期货套期保值中的展期管理有哪些?
在复杂的金融市场环境中,展期作为一种重要的风险管理工具,被广泛应用于期货交易中,特别是当投资者需要对长期资产进行套期保值时。展期的核心思想在于,通过连续替换高流动性的近月期货合约来替代流动性较差的远月合约,…...

如何通过参考文献找到原文
当只有参考文献想要获取原文时,通常会用到以下方法: 举例参考文献1. 杨忠华,周勃,宁宝宽,等.面向新能源产业的专业研究生研创能力培养实践探索——基于“政产学研用”融合驱动[J].高教学刊,2024,10(23):19-22.DOI:10.19980/j.CN23-1593/G4.2024.23.004…...

春秋云境 | SQL | CVE-2022-4230
目录 靶标介绍 开启靶场 wpscan漏洞介绍 查询数据库表名 查询表中字段名 查询字段下数据 靶标介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数,这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下,具有管理选项功能 (ad…...

3.串口(UART)
串口理论部分可看51部分:链接 数据帧 帧头(2字节,例如AA、BB) 数据长度(2字节) 数据 CRC16校验(2字节) 帧尾(2字节) 代码编写 串口一发送命令控制LED灯(PB5、PE5) LED灯、串口、…...

macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载
macOS Sonoma 14.6.1 (23G93) Boot ISO 原版可引导镜像下载 2024 年 8 月 8 日凌晨,macOS Sonoma 14.6.1 发布,本更新包含了重要的错误修复,并解决了导致高级数据保护无法启用或停用的问题。同时带来了 macOS Ventura 13.6.9 安全更新。 本…...

论企业私域流量运营中的玩法创新与开源 AI 智能名片 O2O 商城小程序的应用
摘要:本文旨在探讨企业在构建私域流量池时的多种玩法策略,并着重分析如何针对不同类型客户制定个性化方案。同时,引入开源 AI 智能名片 O2O 商城小程序这一工具,阐述其在私域流量运营中的重要作用和价值,为企业提升运营…...