Ради интереса я написал следующие универсальные помощники для записи произвольных 2-мерных массивов в двоичные потоки:
namespace arraystream
{
template <class T, size_t M> std::istream& operator>>(std::istream& is, const T (&t)[M])
{ return is.read ((char*) t, M*sizeof(T)); }
template <class T, size_t M> std::ostream& operator<<(std::ostream& os, const T (&t)[M])
{ return os.write((char*) t, M*sizeof(T)); }
template <class T, size_t N, size_t M> std::istream& operator>>(std::istream& is, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) is >> tt[i]; return is; }
template <class T, size_t N, size_t M> std::ostream& operator<<(std::ostream& os, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) os << tt[i]; return os; }
}
Вы можете использовать их как в своем коде:
char c [23] [5];
float f [7] [100];
uint16_t r2[100][100]; // yes that too
std::ofstream ofs("output.raw", std::ios::binary || std::ios::out);
ofs << c << f << r2;
ofs.flush();
ofs.close();
////
std::ifstream ifs("output.raw", std::ios::binary || std::ios::in);
ifs >> c >> f >> r2;
ifs.close();
Единственным незначительным недостатком здесь является то, что если бы вы объявляли их в пространстве имен std (или use
их все время), компилятор попытался бы использовать эти перегрузки и для записи std::cout << "hello world"
(то есть char[12]
прямо там). Я решил явно use
пространство имен arraystream
, где это необходимо, см. Полный пример ниже.
Вот полный скомпилированный пример, показывающий с помощью хэша контрольной суммы, что считанные данные действительно идентичны. Повышение не требуется для использования этих помощников. Я использую boost :: random, чтобы получить набор случайных данных, boost :: hash, чтобы выполнить контрольную сумму. Вы можете использовать любой генератор случайных чисел, и, возможно, вместо этого использовать внешний инструмент контрольной суммы.
Без лишних слов:
#include <fstream>
#include <boost/random.hpp>
#include <boost/functional/hash.hpp>
namespace arraystream
{
template <class T, size_t M> std::istream& operator>>(std::istream& is, const T (&t)[M]) { return is.read ((char*) t, M*sizeof(T)); }
template <class T, size_t M> std::ostream& operator<<(std::ostream& os, const T (&t)[M]) { return os.write((char*) t, M*sizeof(T)); }
template <class T, size_t N, size_t M> std::istream& operator>>(std::istream& is, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) is >> tt[i]; return is; }
template <class T, size_t N, size_t M> std::ostream& operator<<(std::ostream& os, const T (&tt)[N][M])
{ for (size_t i=0; i<N; i++) os << tt[i]; return os; }
}
template <class T, size_t N, size_t M>
size_t hash(const T (&aa)[N][M])
{
size_t seed = 0;
for (size_t i=0; i<N; i++)
boost::hash_combine(seed, boost::hash_range(aa[i], aa[i]+M));
return seed;
}
int main()
{
uint16_t data[100][100];
{
// make some (deterministic noise)
boost::mt19937 rand(0);
for (int i=0; i<100; i++) for (int j=0; j<100; j++) data[i][j] = rand();
}
{
// write a file
std::ofstream ofs;
ofs.open("output.raw", std::ios::out | std::ios::binary);
using namespace arraystream;
ofs << data;
ofs.flush();
ofs.close();
}
uint16_t clone[100][100];
{
// read a file
std::ifstream ifs;
ifs.open("output.raw", std::ios::in | std::ios::binary);
using namespace arraystream;
ifs >> clone;
ifs.close();
}
std::cout << "data: " << hash(data) << std::endl;
std::cout << "clone: " << hash(clone) << std::endl;
return 0;
}