SLISC 的 matt/matb 文件格式

                     

贡献者: addis

  • 本文存在未完成的内容。
预备知识 SLISC 简介

   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();

    // 此时可以对比读取的变量是否和保存的变量一致
}

1. 文件格式

   我们先介绍二进制格式 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)。

2. Matb 类

// 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();
};

3. 修改模式

   打开 matb 的模式除了 "r", "w" 外还可以是 "m",表示 modify。在该模式下,打开文件后可以对变量进行增加,删除,修改等操作。该功能尚未完善。

4. 其他工具

   可执行文件 SLISC/util/matbinfo 可以显示 matb 文件中的所有变量信息,用法是 matbinfo 文件名.matb

   可执行文件 SLISC/util/matt2matbmatb2matt 可以把 matt 文件和 matb 文件互相转换,例如 matb2matt -d -r 文件名.matb 会生成 文件名.matt。其中 -d 选项在转换后把原文件删除,如果 文件名.matt 已经存在,-r 选项会重新转换并将其替换。

   可执行文件 SLISC/util/matb_q2d 可以把 matb 文件中所有四精度数值转换为双精度(包括 QdoubQcomp)。这样可以方便在不支持四精度的语言中读取(例如 Matlab)。

   Matlab 程序 SLISC/util/mattload.mmatbload.m 分别可以在 Matlab 中读取 mattmatb 文件。

                     

© 小时科技 保留一切权利