2016-05-01 4 views
1

Я пытаюсь просто сохранить и перезагрузить текущее время в файле. Например:Сохранение и загрузка std :: chrono :: time_point в файл

std::ifstream ifs(solar_system_cache_file, 
     std::ios::in | std::ios::binary); 

if (!ifs.is_open()) { 
    return false; 
} 

std::chrono::system_clock::time_point cache_valid_time; 
ifs >> cache_valid_time; 

if (std::chrono::system_clock::now() < cache_valid_time) { 
    std::cout << "Cache is VALID." << std::endl; 
} 
ifs.close(); 
return true; 

и

std::ofstream ofs(solar_system_cache_file, 
     std::ios::out | std::ios::binary); 

if (!ofs.is_open()) 
    return; 

ofs << std::chrono::system_clock::now() + 12h; 
ofs.close(); 

Такого рода вещи не сложно, но я смотрел вокруг в течение нескольких часов, и я не могу найти нужную информацию. Есть пример того, как делать с использованием duration_cast<long, std::milli>, но std::chrono чрезвычайно изогнут и трудно ориентироваться (и переваривать).

В двух словах, я считаю, что нужно направить текущее время на long (или на какой-то аналогичный большой тип) и сохранить это. При десериализации времени мне просто нужно вернуть его обратно в time_point. Это звучит достаточно легко, но я не могу этого сделать.

И наконец, просто прокладка трубопровода в fstream дает обычную ошибку invalid operands to binary expression.

Любая помощь приветствуется или ссылки на хорошие учебники/руководства. Спасибо

+0

Вы хотите, чтобы сериализованный формат был доступен для человека? – ildjarn

+0

Нет, это в двоичной форме. Я отправил свое решение в качестве ответа, не стесняйтесь, конечно, задуматься над проблемой :) – scx

ответ

3

Если вы хотите двоичную сериализацию, не используйте форматированные текстовые процедуры для реализации сериализации. : -]

Часы time_point - это всего лишь обертка вокруг арифметического типа, которая представляет собой количество периодов некоторой единицы времени, прошедших с момента времени. Все, что вам действительно нужно сделать, это сериализации, что арифметическое значение в его двоичном виде:

Сохранение

using namespace std::chrono_literals; 

std::ofstream ofs(solar_system_cache_file, std::ios::binary); 
if (!ofs.is_open()) { 
    return; 
} 

auto const cache_time = (std::chrono::system_clock::now() + 12h).time_since_epoch().count(); 
ofs.write(reinterpret_cast<char const*>(&cache_time), sizeof cache_time); 
ofs.close(); 

Загрузка

using clk_t = std::chrono::system_clock; 

std::ifstream ifs(solar_system_cache_file, std::ios::binary); 
if (!ifs.is_open()) { 
    return false; 
} 

clk_t::rep file_time_rep; 
if (!ifs.read(reinterpret_cast<char*>(&file_time_rep), sizeof file_time_rep)) { 
    return false; 
} 
ifs.close(); 

clk_t::time_point const cache_valid_time{clk_t::duration{file_time_rep}}; 
std::time_t const file_time = clk_t::to_time_t(cache_valid_time); 
std::cout << std::ctime(&file_time); 

Обратите внимание, что передача openmode::in к входному потоку и openmode::out к выходному потоку является избыточным.

Кроме того, важно, обратите внимание, что двоичная сериализация не является переносимым:

  1. Тип std::chrono::system_clock::rep определяется реализацией - единственным требованием является то, что это знаковое арифметический тип - и поэтому может меняться от одного компилятора/stdlib/config к следующему.
  2. Даже если вы контролировали тип представления с помощью std::chrono::duration_cast, то континентность интегральных типов и представление типов с плавающей точкой в ​​целом зависит от архитектуры.

Следовательно, вы можете полагаться только на десериализацию данных с кодом, который был построен с той же архитектурой/компилятором/stdlib/config, что и код сериализации.

+0

Кроме того, эпоха может меняться даже от запуска до запуска (для 'system_clock' это не на практике, но нет никакой гарантии). –

+0

Отличный ответ, спасибо. Я довольно смущен о 'rep', что он должен представлять? – scx

+0

@Socapex: 'rep' - это тип, используемый для хранения количества единиц времени, прошедших с эпохи. В моей системе 'system_clock :: period' является' std :: nano', а 'system_clock :: rep'' long long', поэтому сериализуемое значение представляет собой «длинный длинный», содержащий количество наносекунд, прошедших с эпохи. – ildjarn

1

Хорошо, после того, как я снова начал играть, я наконец получил его.

Ответ std::time_t, и это друзья std::chrono::system_clock::from_time_t и std::chrono::system_clock::to_time_t.

Итак, чтобы сохранить, все, что вам нужно сделать, это преобразовать ::now() в time_t и передать его в ваш файл. Чтобы загрузить, выполните обратное, используя from_time_t.

Сохранение

std::ofstream ofs(solar_system_cache_file, 
     std::ios::out | std::ios::binary); 

if (!ofs.is_open()) 
    return; 

auto cache_time = std::chrono::system_clock::now() + 12h; 
ofs << std::chrono::system_clock::to_time_t(cache_time); 
ofs.close(); 

Загрузка

std::ifstream ifs(solar_system_cache_file, 
     std::ios::in | std::ios::binary); 

if (!ifs.is_open()) { 
    return false; 
} 

std::time_t file_time; 
ifs >> file_time; 
std::cout << std::ctime(&file_time); 

auto cache_valid_time = std::chrono::system_clock::from_time_t(file_time); 
ifs.close(); 

Довольно просто в конце концов, ура!

+1

Это нормально, если вас устраивает точность 'time_t' (в текстовой форме), что обычно составляет секунды. Ответ ildjarn точно соответствует тем единицам, на которые ваш 'system_clock' измеряет (наносекунды в вашем случае), и использует более компактную двоичную форму. –