2013-12-19 6 views
1

Моя заявка в настоящее время входит в очень простой способ:Ограничить размер файла фильтра?

void Log::create(const std::string& path, bool append) 
{ 
    if(append) 
    m_log.open(path.c_str(),std::ios_base::out | std::ios_base::app); 
    else 
     m_log.open(path.c_str(),std::ios_base::out | std::ios_base::trunc); 
} 

std::ofstream& Log::get() 
{ 
    return m_log; 
} 

void Log::write(const std::string& what) 
{ 
    get() << "[" << TimeOfDay::getDate() << "] "; 
    get() << what << std::endl; 
} 

void Log::write(const std::string& where, const std::string& what) 
{ 
    get() << "[" << TimeOfDay::getDate() << "] "; 
    get() << "[" << where << "] " << what << std::endl; 
} 

std::ofstream& Log::write() 
{ 
    get() << "[" << TimeOfDay::getDate() << "] "; 
    return get(); 
} 

std::ofstream Log::m_log; 

Это приложение работает на сервере. Теперь, если журнал превышает определенный размер файла, я хочу прекратить ведение журнала.

Есть ли способ сделать это без повышения или других библиотек?

Благодаря

+1

Не могли бы вы просто отслеживать количество строк, написанных путем увеличения счетчика в рамках различных перегрузок 'write()'? Boost.Filesystem имеет функцию ['file_size'] (http://www.boost.org/libs/filesystem/doc/reference.html#file_size), которая делает то, что вы хотите. MSVC 2013 поставляется с реализацией '', основанной на Boost, поэтому она должна предлагать ту же функциональность, если вы используете этот компилятор. – Praetorian

ответ

3

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

class limitbuf 
    : public std::streambuf { 
    std::streambuf* sbuf; 
    size_t   size; 
    size_t   limit; 
    char   buffer[1024]; 
public: 
    limitbuf(std::streambuf* sbuf, size_t limit) 
     : sbuf(sbuf), limit(limit), size(0) 
    { 
     this->setp(buffer, buffer + 1023); 
    } 
    int overflow(int c) { 
     if (c != std::char_traits<char>::eof()) { 
      this->pptr() = std::char_traits<char>::to_char_type(c); 
      this->pbump(1); 
     } 
     return this->sync() == 0 
      ? std::char_traits<char>::not_eof(c) 
      : std::char_traits<char>::eof(); 
    } 
    int sync() { 
     if (this->size < limit) { 
      this->size += this->sbuf->sputn(this->pbase(), 
       std::min(
        size_t(this->pptr() - this->pbase()), 
        this->limit - this->size) 
       ); 
      this->sbuf->pubsync(); 
     } 
     this->setp(this->pbase(), this->epptr()); 
     return 0; 
    } 
}; 

Просто установите этот поток буфер в качестве фильтра в файл журнала, и это должно быть ограничение в какой-то подходящий размер:

std::ofstream out("some.log", 16384); 
limitbuf  sbuf(out.rdbuf()); 
std::ostream log(&sbuf); 

Основная идея этого потока буфера является довольно простой : данные буфера внутренне и записаны на переполнение буфера или на флеш:

  • Когда буфер установлен с setp() переливается поток вызывает overflow(c) с следующий символ, который должен быть написан (или, возможно, с std::char_traits<char>::eof()). Поскольку te stream buffer был указан о буфере, один символ меньше, чем фактически доступен, в буфер добавляется переполняющий символ, и общий буфер сбрасывается.
  • Когда буфер сбрасывается (например, с использованием std::endl на std::ostream, записывающемся в этот буфер), функция sync() вызывается. Его просто состоит в том, чтобы писать символы, которые в настоящее время буферизованы. Код просто видит, есть ли место для записи чего-либо, и записывает символ, если есть свободное место. Член size поддерживает, сколько символов записано, и limit настроен для указания того, сколько данных должно быть записано.

Если буфер потока должен делать больше, чем просто ограничивать вывод, может потребоваться изменить логику того, что происходит, если пространства больше нет. Например, если есть оставшиеся символы, которые не могут быть записаны, буфер потока может решить открыть новый файл (и, возможно, переместить другие файлы).

+0

Мне также нужно иметь возможность переместить журнал, если он заполнен, а затем вместо него будет создан новый журнал. – jmasterx

+0

@Milo: вы не упомянули это требование раньше ... Во всяком случае: техника примерно такая же. Вероятно, вы сохраните 'std :: filebuf' в буфере потока, который используется для ведения журнала, и введите базовое имя в качестве конфигурации. В 'sync()' вы тогда не просто прекращаете запись, а скорее закрываете существующий файл, переименовывая существующие журналы, возможно, до предела, и открываете новый файл и записываете на него. –

+0

@jrok: er, yes ... (исправлено) –

Смежные вопросы