std::string
слишком сложная структура данных, чтобы, к сожалению, просто записывать в файл.В простейшем случае, string
- это указатель на массив символов и целое число, хранящее длину массива.Когда вы пишете указатель на файл, вы пишете адрес, а не данные по адресу.Когда вы читаете string
в последнем случае, шансы очень хороши, вы получаете устаревший адрес, указывающий на память, которой не владеет программа, и много неприятных ошибок.Хуже, если адрес обратной ссылки указывает на то, что существует в программе.Как правило, они не сразу дают сбой и уводят вас от реальной ошибки, потому что коррупционер сидит в другом фрагменте кода, самодовольно насвистывая, когда вы обвиняете и отлаживаете неправильный код.В любом случае доступ к памяти, которая не была назначена указателю, вызывает Неопределенное поведение , и с UB все может произойти.Не рассчитывайте на сбои или непротиворечивость.
Как правило, вы будете использовать ваши operator <<
перегрузки для сериализации структуры в файл, а не пытаться выполнить двоичную запись.Если вам нужно делать двоичные записи, вам нужно создать протокол, который описывает, как данные должны быть записаны и прочитаны.
Протокол будет представлять собой набор функций, которые преобразуют более простые типы данных в и из их файла.эквиваленты.
Типичный метод написания string
состоит в том, чтобы сначала записать длину string
, а затем записать содержимое string
.Что-то вроде
uint32 len = str.length(); //fixed width length
len = htonl(len); // fixed endian
myfile.write((char*) &len, sizeof(len)); //write length
myfile.write(str.data(), str.length()); //write string
И чтение
uint32 len; //fixed width length
myfile.read((char*) &len, sizeof(len)); //read length
len = ntohl(len); // unfix endian
std::string str(len, ' '); //string and allocate size
myfile.write(str.data(), len); //read string C++17 or
//myfile.write(&str[0], len); //read string before C++17
объединяет эти внутренние функции, и вы начали использовать свой протокол.Добавьте к ним функции для других типов данных, которые вам нужно сохранить.
Эти функции затем вызываются функциями, которые преобразуют большие типы данных и вплоть до тех пор, пока вы не достигнете самой сложной структуры, которую вам нужно написать.Для массива используйте цикл.Если у вас есть длина переменного размера, добавьте префикс длины, как и string
.
. Примечание: при чтении или записи чисел необходимо следить за тем, чтобы число было известного фиксированного размера.int
, например , can be any size 16 bits or greater so long at it's not larger than
long . You don't necessarily know that the file reader will be using the same sized
int`, поэтому вы должны предпочесть Fixed Width Integer достаточно большой, чтобы хранить требуемые значения.Разные компьютеры также могут хранить свою двоичную информацию в разных порядках.Это называется Byte Order или Endian .Убедитесь, что все используют один и тот же порядковый номер.