贡献者: addis
SLISC 库提供了两种特殊的文件格式用于储存各种变量和矩阵,每个文件可以存如多个不同的变量(包括矩阵)并指定名称,读取时可以指定要读取的变量名。两种文件分别使用拓展名 .matt
和 .matb
。其中 mat
表示 matrix,t
表示 text,b
表示 binary。顾名思义,第一种是文本文件,第二种是二进制文件。二进制文件具有占用硬盘空间少(大约是文本文件的 1/3),读写速度快的优点。文件格式简单,在任何其他语言中都可以轻易地写出读写程序。
以下给一个 matb 文件的读写例子,也可以把例子中的 matb 换成 matt。
#include "SLISC/matb.h"
using namespace slisc;
int main()
{
// 随便初始化一些变量, 目前支持 SLISC 库中的绝大部分标量和密矩阵
Int i = 1; Doub d = 3.1; Comp c(1, 2);
VecInt v(3); linspace(3, 1, 3); CmatInt a(2,2); linspace(a);
Matb matb("test.matb", "w"); // 打开 matb 文件, 使用写入模式
// 相当于 Matb matb; matb.open("test.matb", "w");
save(i, "i", matb); // 保存变量, 指定变量名, 可以是任意字符串
save(d, "d", matb); // 注意同个文件中保存的变量名不能重复
save(c, "c", matb);
save(v, "c", matb);
save(a, "a", matb);
matb.close(); // 关闭文件。
// 在 destructor 中会自动调用, open() 时也会自动调用
Int i1; Doub d1; Comp c1; VecInt v1(3); CmatInt a1;
matb.open("test.matb", "w"); // 重新用读取模式打开文件
// 读取变量, 可以按照任何顺序, 不需要全部读取
// 矩阵会被自动 resize()
load(i1, "i", matb);
load(d1, "d", matb);
load(c1, "c", matb);
load(v1, "c", matb);
load(a1, "a", matb);
matb.close();
// 此时可以对比读取的变量是否和保存的变量一致
}
我们先介绍二进制格式 matb。matb 文件使用 little endian 储存(通常的 x86 处理器都满足)。所有整数都用 long long
(8 字节有符号整型)储存, 每个变量的前 8 个字节是变量名的长度 Nname
,然后是 Nname
字节的变量名,紧接着是 8 个字节的矩阵元类型编号(对照表未完成,见 SLISC/preprocessor/type_num.m
),8 个字节的矩阵维度 Ndim
(标量的维数是 0,向量维度是 1)接着 8*Ndim
字节记录每个维度的长度(标量不需要)。最后,再记录 N * sizeof(元素类型)
,其中 N
是元素个数,等于各个维度的长度相乘。
在文件的最后,若一共有 Nvar
个变量,那么就用 Nvar*8
字节记录下每个变量的第一个字节在文件中的字节数(第一个变量总是从第 0 个字节开始)(未完成:目前是倒序的)(另外这些信息只对 matt 有必要),然后再用 8 字节记录下 Nvar
,这是为了读取时查找方便。最后为了验证文件的完整性,用 16 字节写入字符串 "Matb_End_of_File"
。该字符串用于读取时验证文件的完整性,若不存在则说明文件写入没有完成。事实上 matb
不需要记录该信息,因为逐个变量跳查已经足够快了。matt
使用该信息则可以加快查找变量的速度(因为每个矩阵元在文件中的长度是不等的)。
对于文本格式 matt
,每个整数或浮点数直接转换成字符串写入文本,每两个数之间使用空格隔开,复数则写成两个相邻的数(未完成:现在代码并不是这么做的,而是类似 1+2i
)。
// all non-data intergers in file are Llong
class Matb {
public:
Matb();
Matb(Str_I fname, Char_I rw);
Char m_rw; // 模式
ifstream m_in;
ofstream m_out;
Llong m_filesize; // 文件大小
Str m_fname; // 文件名
vecStr m_name; // 变量名
vecLlong m_type; // 变量类型
vector<vecLlong> m_size; // 矩阵尺寸
vecStr m_data; // 矩阵元二进制数据(仅 "m" 模式使用)
vecLlong m_ind; // 变量位置
void open(Str_I fname, Char_I rw); // 打开文件
Bool isopen(); // 文件是否打开
// 内部函数
void read_data(); // 读取到 m_data
void write_data(Str_I fname); // 写入到 m_data
Long size() const; // 变量个数
Long data_size(Long_I i) const; // 第 i 个变量的 m_data 长度
void get_profile(); // 读取变量信息
Long data_pos(Long_I var_ind) const; // 第 i 个变量在文件中的位置
Long search(Str_I name); // 搜索变量编号, 如果不存在返回 -1
~Matb();
};
打开 matb 的模式除了 "r", "w"
外还可以是 "m"
,表示 modify。在该模式下,打开文件后可以对变量进行增加,删除,修改等操作。该功能尚未完善。
可执行文件 SLISC/util/matbinfo
可以显示 matb 文件中的所有变量信息,用法是 matbinfo 文件名.matb
。
可执行文件 SLISC/util/matt2matb
和 matb2matt
可以把 matt 文件和 matb 文件互相转换,例如 matb2matt -d -r 文件名.matb
会生成 文件名.matt
。其中 -d
选项在转换后把原文件删除,如果 文件名.matt
已经存在,-r
选项会重新转换并将其替换。
可执行文件 SLISC/util/matb_q2d
可以把 matb 文件中所有四精度数值转换为双精度(包括 Qdoub
和 Qcomp
)。这样可以方便在不支持四精度的语言中读取(例如 Matlab)。
Matlab 程序 SLISC/util/mattload.m
和 matbload.m
分别可以在 Matlab 中读取 matt
和 matb
文件。