433 lines
16 KiB
C++
433 lines
16 KiB
C++
/********************************************************
|
||
* ██████╗ ██████╗████████╗██╗
|
||
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
||
* ██║ ███╗██║ ██║ ██║
|
||
* ██║ ██║██║ ██║ ██║
|
||
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
||
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
||
* Geophysical Computational Tools & Library (GCTL)
|
||
*
|
||
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
|
||
*
|
||
* GCTL is distributed under a dual licensing scheme. You can redistribute
|
||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation, either version 2
|
||
* of the License, or (at your option) any later version. You should have
|
||
* received a copy of the GNU Lesser General Public License along with this
|
||
* program. If not, see <http://www.gnu.org/licenses/>.
|
||
*
|
||
* If the terms and conditions of the LGPL v.2. would prevent you from using
|
||
* the GCTL, please consider the option to obtain a commercial license for a
|
||
* fee. These licenses are offered by the GCTL's original author. As a rule,
|
||
* licenses are provided "as-is", unlimited in time for a one time fee. Please
|
||
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
|
||
* to include some description of your company and the realm of its activities.
|
||
* Also add information on how to contact you by electronic and paper mail.
|
||
******************************************************/
|
||
|
||
#ifndef _GCTL_NATIVE_IO_H
|
||
#define _GCTL_NATIVE_IO_H
|
||
|
||
#include "../core/spmat.h"
|
||
#include "file_io.h"
|
||
|
||
namespace gctl
|
||
{
|
||
/**
|
||
* @brief 从GCTL定义的二进制文件(后缀为.ar)导入数据到数组
|
||
*
|
||
* @warning 此函数在导入元素前会先清空原来的数组,再重新初始化数组
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param out_arr 输出的数组
|
||
* @param[in] info_ptr 存储头信息的字符串指针,若不为空则保存头信息到字符串
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void read_binary2array(std::string filename, array<T> &out_arr,
|
||
std::string *info_ptr = nullptr)
|
||
{
|
||
std::ifstream infile;
|
||
open_infile(infile, filename, ".ar", std::ios::in|std::ios::binary);
|
||
|
||
int info_size;
|
||
std::string head_info, ele_name, type_name = typeid(T).name();
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
if (info_size != 0)
|
||
{
|
||
head_info.resize(info_size);
|
||
infile.read((char*)head_info.c_str(), info_size);
|
||
}
|
||
|
||
if (info_ptr != nullptr)
|
||
{
|
||
*info_ptr = head_info;
|
||
}
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
ele_name.resize(info_size);
|
||
infile.read((char*)ele_name.c_str(), info_size);
|
||
|
||
// 首先读入一个整形并与元素的大小进行比较
|
||
int ele_size;
|
||
infile.read((char*)&ele_size, sizeof(int));
|
||
if (ele_size != sizeof(T) || ele_name != type_name)
|
||
{
|
||
throw runtime_error("Incompatible element size or name. From gctl::read_binary2array(...)");
|
||
}
|
||
|
||
// 读入元素个数
|
||
int in_size;
|
||
infile.read((char*)&in_size, sizeof(int));
|
||
if (in_size <= 0)
|
||
{
|
||
throw runtime_error("No element found. From gctl::read_binary2array(...)");
|
||
}
|
||
|
||
out_arr.resize(in_size);
|
||
infile.read((char*)out_arr.get(), sizeof(T)*in_size);
|
||
infile.close();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief 保存数组数据到GCTL定义的二进制文件(后缀为.ar)
|
||
*
|
||
* 二进制文件格式:
|
||
* 后缀名称:.ar
|
||
* 格式:1. 整形值,等于头信息的长度
|
||
* 格式:2. 字符串,头信息(所保存数据的必要说明)
|
||
* 格式:3. 整形值,等于数组元素的typeid名称的长度
|
||
* 格式:4. 字符串,数组元素的typeid名称(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:5. 整形值,数组元素的sizeof长度(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:6. 整形值,输出的数组元素的个数
|
||
* 格式:7. 输出的数组元素的列表
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param[in] in_arr 输入的数组
|
||
* @param[in] head_info 需要保存的头信息
|
||
* @param[in] st 数组保存的起始位置,默认为数组开始位置
|
||
* @param[in] ed 数组保存的结束位置,默认为数组结束位置
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void save_array2binary(std::string filename, const array<T> &in_arr,
|
||
std::string head_info = "No Head Info", int st = 0, int ed = 0)
|
||
{
|
||
if (in_arr.empty())
|
||
{
|
||
throw length_error("The operating array is empty. From gctl::save_array2binary(...)");
|
||
}
|
||
|
||
if (st < 0)
|
||
{
|
||
throw out_of_range("Invalid index. From gctl::save_array2binary(...)");
|
||
}
|
||
|
||
if (ed == 0) ed = in_arr.size();
|
||
|
||
if (ed < 0 || ed > in_arr.size() || st >= ed)
|
||
{
|
||
throw out_of_range("Invalid index. From gctl::save_array2binary(...)");
|
||
}
|
||
|
||
std::ofstream outfile;
|
||
open_outfile(outfile, filename, ".ar", std::ios::out|std::ios::binary);
|
||
|
||
int info_size = head_info.size();
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)head_info.c_str(), info_size);
|
||
|
||
const std::type_info &tinfo = typeid(T);
|
||
std::string ele_name = tinfo.name();
|
||
info_size = ele_name.size();
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)ele_name.c_str(), info_size);
|
||
|
||
int ele_size = sizeof(T);
|
||
outfile.write((char*)&ele_size, sizeof(int));
|
||
|
||
int out_size = ed - st;
|
||
outfile.write((char*)&out_size, sizeof(int));
|
||
outfile.write((char*)in_arr.get(st), sizeof(T)*out_size);
|
||
outfile.close();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief 从GCTL定义的二进制文件(后缀为.mat)导入数据到数组
|
||
*
|
||
* @warning 此函数在导入元素前会先清空原来的数组,再重新初始化数组
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param out_arr 输出的数组
|
||
* @param[in] info_ptr 存储头信息的字符串指针,若不为空则保存头信息到字符串
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void read_binary2matrix(std::string filename, matrix<T> &out_arr,
|
||
std::string *info_ptr = nullptr)
|
||
{
|
||
std::ifstream infile;
|
||
open_infile(infile, filename, ".mat", std::ios::in|std::ios::binary);
|
||
|
||
int info_size;
|
||
std::string head_info, ele_name, type_name = typeid(T).name();
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
if (info_size != 0)
|
||
{
|
||
head_info.resize(info_size);
|
||
infile.read((char*)head_info.c_str(), info_size);
|
||
}
|
||
|
||
if (info_ptr != nullptr)
|
||
{
|
||
*info_ptr = head_info;
|
||
}
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
ele_name.resize(info_size);
|
||
infile.read((char*)ele_name.c_str(), info_size);
|
||
|
||
// 首先读入一个整形并与元素的大小进行比较
|
||
int ele_size;
|
||
infile.read((char*)&ele_size, sizeof(int));
|
||
if (ele_size != sizeof(T) || ele_name != type_name)
|
||
{
|
||
throw runtime_error("Incompatible element size. From gctl::read_binary2matrix(...)");
|
||
}
|
||
|
||
// 读入元素个数
|
||
int in_rowsize, in_colsize;
|
||
infile.read((char*)&in_rowsize, sizeof(int));
|
||
infile.read((char*)&in_colsize, sizeof(int));
|
||
if (in_rowsize <= 0 || in_colsize <= 0)
|
||
{
|
||
throw runtime_error("No element found. From gctl::read_binary2matrix(...)");
|
||
}
|
||
|
||
out_arr.resize(in_rowsize, in_colsize);
|
||
for (int i = 0; i < in_rowsize; i++)
|
||
{
|
||
infile.read((char*)out_arr.get(i), sizeof(T)*in_colsize);
|
||
}
|
||
|
||
infile.close();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief 保存数组数据到GCTL定义的二进制文件(后缀为.mat)
|
||
*
|
||
* 二进制文件格式:
|
||
* 后缀名称:.mat
|
||
* 格式:1. 整形值,等于头信息的长度
|
||
* 格式:2. 字符串,头信息(所保存数据的必要说明)
|
||
* 格式:3. 整形值,等于数组元素的typeid名称的长度
|
||
* 格式:4. 字符串,数组元素的typeid名称(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:5. 整形值,数组元素的sizeof长度(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:6. 整形值,输出的数组元素的行数
|
||
* 格式:7. 整形值,输出的数组元素的列数
|
||
* 格式:8. 输出的数组元素的列表
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param[in] in_arr 输入的数组
|
||
* @param[in] head_info 需要保存的头信息
|
||
* @param[in] r_st 开始的行索引,默认为数组开始位置
|
||
* @param[in] r_ed 结束的行索引,默认为数组结束位置
|
||
* @param[in] c_st 开始的列索引,默认为数组开始位置
|
||
* @param[in] c_ed 开始的列索引,默认为数组开始位置
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void save_matrix2binary(std::string filename, const matrix<T> &in_arr,
|
||
std::string head_info = "No Head Info", int r_st = 0, int r_ed = 0,
|
||
int c_st = 0, int c_ed = 0)
|
||
{
|
||
if (in_arr.empty())
|
||
{
|
||
throw runtime_error("The input array is empty. From gctl::save_matrix2binary(...)");
|
||
}
|
||
|
||
if (r_st < 0 || c_st < 0 || r_ed < 0 || c_ed < 0 ||
|
||
r_ed > in_arr.row_size() || c_ed > in_arr.col_size())
|
||
{
|
||
throw invalid_argument("Invalid index. From gctl::save_matrix2binary(...)");
|
||
}
|
||
|
||
if (r_ed == 0) r_ed = in_arr.row_size();
|
||
if (c_ed == 0) c_ed = in_arr.col_size();
|
||
|
||
std::ofstream outfile;
|
||
open_outfile(outfile, filename, ".mat", std::ios::out|std::ios::binary);
|
||
|
||
int info_size = head_info.size();
|
||
int ele_size = sizeof(T);
|
||
int out_rowsize = r_ed - r_st;
|
||
int out_colsize = c_ed - c_st;
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)head_info.c_str(), info_size);
|
||
|
||
const std::type_info &tinfo = typeid(T);
|
||
std::string ele_name = tinfo.name();
|
||
info_size = ele_name.size();
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)ele_name.c_str(), info_size);
|
||
|
||
outfile.write((char*)&ele_size, sizeof(int));
|
||
outfile.write((char*)&out_rowsize, sizeof(int));
|
||
outfile.write((char*)&out_colsize, sizeof(int));
|
||
for (int i = r_st; i < r_ed; i++)
|
||
{
|
||
for (size_t j = c_st; j < c_ed; j++)
|
||
{
|
||
outfile.write((char*)&in_arr[i][j], sizeof(T));
|
||
}
|
||
//outfile.write((char*)in_arr.get(i, c_st), sizeof(T)*(c_ed-c_st));
|
||
}
|
||
outfile.close();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief 从GCTL定义的二进制文件(后缀为.spm)导入数据到稀疏矩阵
|
||
*
|
||
* @warning 此函数在导入元素前会先清空原来的矩阵,再重新初始化数组
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param out_mat 输出的稀疏矩阵
|
||
* @param[in] info_ptr 存储头信息的字符串指针,若不为空则保存头信息到字符串
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void read_binary2spmat(std::string filename, spmat<T> &out_mat,
|
||
std::string *info_ptr = nullptr)
|
||
{
|
||
std::ifstream infile;
|
||
open_infile(infile, filename, ".spm", std::ios::in|std::ios::binary);
|
||
|
||
int info_size;
|
||
std::string head_info, ele_name, type_name = typeid(T).name();
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
if (info_size != 0)
|
||
{
|
||
head_info.resize(info_size);
|
||
infile.read((char*)head_info.c_str(), info_size);
|
||
}
|
||
|
||
if (info_ptr != nullptr)
|
||
{
|
||
*info_ptr = head_info;
|
||
}
|
||
|
||
infile.read((char*)&info_size, sizeof(int));
|
||
ele_name.resize(info_size);
|
||
infile.read((char*)ele_name.c_str(), info_size);
|
||
|
||
// 首先读入一个整形并与元素的大小进行比较
|
||
int ele_size;
|
||
infile.read((char*)&ele_size, sizeof(int));
|
||
if (ele_size != sizeof(T) || ele_name != type_name)
|
||
{
|
||
throw runtime_error("Incompatible element size or name. From gctl::read_binary2spmat(...)");
|
||
}
|
||
// 读入元素个数
|
||
int ele_num, in_rnum, in_cnum;
|
||
T in_zeroval;
|
||
infile.read((char*)&in_rnum, sizeof(int));
|
||
infile.read((char*)&in_cnum, sizeof(int));
|
||
infile.read((char*)&ele_num, sizeof(int));
|
||
infile.read((char*)&in_zeroval, sizeof(T));
|
||
|
||
out_mat.clear();
|
||
out_mat.malloc(in_rnum, in_cnum, in_zeroval);
|
||
|
||
int tmp_rid, tmp_cid;
|
||
T tmp_val;
|
||
|
||
for (int i = 0; i < ele_num; i++)
|
||
{
|
||
infile.read((char*)&tmp_rid, sizeof(int));
|
||
infile.read((char*)&tmp_cid, sizeof(int));
|
||
infile.read((char*)&tmp_val, sizeof(T));
|
||
|
||
out_mat.insert(tmp_rid, tmp_cid, tmp_val);
|
||
}
|
||
infile.close();
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief 保存稀疏矩阵数据到GCTL定义的二进制文件(后缀为.spm)
|
||
*
|
||
* 二进制文件格式:
|
||
* 后缀名称:.ar
|
||
* 格式:1. 整形值,等于头信息的长度
|
||
* 格式:2. 字符串,头信息(所保存数据的必要说明)
|
||
* 格式:3. 整形值,等于数组元素的typeid名称的长度
|
||
* 格式:4. 字符串,数组元素的typeid名称(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:5. 整形值,数组元素的sizeof长度(验证文件所保存数据是否为正确的数据类型)
|
||
* 格式:6. 整形值,输出的数组元素的个数
|
||
* 格式:7. 输出的数组元素的列表
|
||
*
|
||
* @param[in] filename 文件名(不包含文件后缀)
|
||
* @param[in] in_arr 输入的数组
|
||
* @param[in] head_info 需要保存的头信息
|
||
* @param[in] st 数组保存的起始位置,默认为数组开始位置
|
||
* @param[in] ed 数组保存的结束位置,默认为数组结束位置
|
||
*
|
||
* @tparam T 模板类型
|
||
*/
|
||
template <typename T>
|
||
void save_spmat2binary(std::string filename, const spmat<T> &in_mat,
|
||
std::string head_info = "No Head Info")
|
||
{
|
||
std::ofstream outfile;
|
||
open_outfile(outfile, filename, ".spm", std::ios::out|std::ios::binary);
|
||
|
||
int info_size = head_info.size();
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)head_info.c_str(), info_size);
|
||
|
||
const std::type_info &tinfo = typeid(T);
|
||
std::string ele_name = tinfo.name();
|
||
info_size = ele_name.size();
|
||
outfile.write((char*)&info_size, sizeof(int));
|
||
outfile.write((char*)ele_name.c_str(), info_size);
|
||
|
||
int ele_size = sizeof(T);
|
||
outfile.write((char*)&ele_size, sizeof(int));
|
||
|
||
int r_num = in_mat.row_size();
|
||
int c_num = in_mat.col_size();
|
||
int n_num = in_mat.ele_size();
|
||
T zero_val = in_mat.zero_value();
|
||
outfile.write((char*)&r_num, sizeof(int));
|
||
outfile.write((char*)&c_num, sizeof(int));
|
||
outfile.write((char*)&n_num, sizeof(int));
|
||
outfile.write((char*)&zero_val, sizeof(T));
|
||
|
||
array<size_t> rows, cols;
|
||
array<T> vals;
|
||
in_mat.export_coo(rows, cols, vals);
|
||
|
||
for (size_t i = 0; i < rows.size(); i++)
|
||
{
|
||
outfile.write((char*)&rows[i], sizeof(size_t));
|
||
outfile.write((char*)&cols[i], sizeof(size_t));
|
||
outfile.write((char*)&vals[i], sizeof(T));
|
||
}
|
||
outfile.close();
|
||
return;
|
||
}
|
||
};
|
||
|
||
#endif // _GCTL_NATIVE_IO_H
|