Запишите корзину для бумаг в C++

Дополнительно вы должны установить libpango-1.0-0

sudo apt install libpango-1.0-0  
8
задан tshepang 23 September 2014 в 21:38
поделиться

13 ответов

К сожалению, вы не можете обрезать / перезаписать строки в начале файла без перезаписи всего файла.

Новое предложение

Я только что подумал о новом подходе, который может сделай за тебя трюк ...

Вы можете включить небольшой заголовок в свой файл, имеющий следующую структуру.

Изменить: Мусор, я только что описал вариант кольцевого буфера !

Поля заголовка

  • Байты 00–07 (длинные) - Общее (текущее) количество строк, записанных в файл.
  • Байты 08–15 (длинные) - Указатель в начало «фактической» первой строки вашего файла. Первоначально это будет байт после окончания заголовка, но он изменится позже, когда данные будут переопределены. «
  • Байты 16–23 (длинные) - Длина« конечного раздела »файла. Очередной раз, изначально это будет ноль, но изменится позже, когда данные будут переопределены.

Алгоритм чтения (псевдокод)

Считывает весь файл.

Read the header field that points to the start of the "actual" first line
Read the header field that specifies the length of the "end section"
Read every line until the end of the file
Seek to the byte just after the end of the header
Read every line until the "end section" has been fully read

Алгоритм записи (псевдокод)

Записывает произвольное количество новых строк в файл.

Read the header field that contains the total no. of lines in the file
If (line count) + (no. of new lines) <= (maximum no. of lines) Then
    Append new lines to end of file
    Increment header field for line count by (no. of ne lines)
Else
    Append as many lines as possible (up to maximum) to end of file
    Beginning at pointer to first line (in header field), read as many lines as still need to be written
    Find the total byte count of the lines just read
    Set the header field that points to the first line to the next byte in the stream
    Keep writing the new lines to the end of the file, each at a time, until the byte count of the remaining lines is less than the byte count of the lines at the beginning of the file (it may be that this condition is true immediately, in which case you don't need to write any more)
    Write the remaining new lines to the start of the file (starting at the byte after the header)
    Set the header field that contains the length of the "end section" of the file to the number of bytes just written after the header.

Я полностью признаю, что это не очень простой алгоритм! Тем не менее, я считаю, что это довольно элегантно. Дайте мне знать, если что-то из этого, конечно, непонятно. Надеюсь, он должен делать именно то, что вы хотите сейчас.

Исходное предложение

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

Наконец, вы можете вместо этого хотите рассмотреть возможность использования существующей системы регистрации, в зависимости от вашей конкретной цели.

9
ответ дан 5 December 2019 в 06:10
поделиться

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

Например, каждый день вы создаете новый файл журнала с именем `application_2009_05_20.log 'и начинаете писать в него , всегда добавляются.

Как только у вас будет 14-дневный журнал файлов, вы начинаете удалять самые старые.

7
ответ дан 5 December 2019 в 06:10
поделиться

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

  1. реализовать строчно-ориентированную оболочку вокруг файла

  2. переключиться на некоторую строку -ориентированное устройство. Я только что подумал: в SQLite есть несколько хороших оболочек C ++.

5
ответ дан 5 December 2019 в 06:10
поделиться

Простое решение:

  1. Установите какой-то разделитель для строк.
  2. Каждый раз, когда вы добавляете новую строку, просто перезаписывайте весь текст, начиная с текущей строки, пока он не достигнет разделителя.
  3. Конец файла является особым случаем и может иметь некоторые дополнения для сохранения постоянного размера файла.

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

«Умное» решение (вариант решения, приведенного выше):

Просто используйте тот же трюк, который иногда используется для дек. Просто явно оберните от начала файла до конца, но следите за тем, где находится начало / конец файла. Вы можете написать служебную программу для преобразования этого файла в стандартный, если хотите прочитать его программой, которая его не поддерживает. Это решение ДЕЙСТВИТЕЛЬНО легко реализовать, но мне больше нравится версия выше.

Уродливое решение:

Добавляя строки, добавьте умеренное количество отступов к каждой добавляемой строке.

Каждый раз, когда вы хотите добавить новая строка, выполните следующие действия:

  1. Определите длину текущей строки, включая заполнение. Обратите внимание, что начало текущей строки совпадает с концом предыдущей строки, не включая отступы.
  2. Если текущая строка достаточно длинна, чтобы поместиться в строке, на которой вы находитесь, вставьте ее. Добавьте левый отступ к конец предыдущей строки равен 1/3 любого лишнего пространства, а правый отступ равен 2/3 любого лишнего пространства.
  3. Если текущая строка недостаточно длинна, чтобы поместиться в строке, на которой вы находитесь, сместите строки впереди вас (съедая их заполнение), пока их не станет достаточно.
  4. Если на шаге 3 достигнут какой-то порог, перепишите все файл с дополнительным заполнением.

Обратите внимание, что это будет работать очень плохо, если ваши строки не будут достаточно последовательными по длине. Более простое решение - гарантировать, что строки имеют постоянную длину (но таким образом можно создать многострочные «линии» на случай, если вы превысите эту длину.

1
ответ дан 5 December 2019 в 06:10
поделиться

Используйте кольцевой буфер и записывайте буфер в файл для каждого добавления.

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

Простая реализация кольцевого буфера с выводом в файл:

// GLOBALS ( final implementation should not use globals )
#define MAX_CHARS_PER_LINE (1024)
#define MAX_ITEMS_IN_CIRCULARBUF (4) // must be power of two
char    lineCircBuf[MAX_ITEMS_IN_CIRCULARBUF][MAX_CHARS_PER_LINE];
int     lineCircBuf_add = 0;
int     lineCircBuf_rmv = 0; // not being used right now
uint32_t lineCircBuf_mask = MAX_ITEMS_IN_CIRCULARBUF-1;
char    FILENAME[] = "lineCircBuf.txt";
FILE *  ofp = NULL;

int addLine(char * str) {
    int i;

    // Error checking
    if( strlen(str) > MAX_CHARS_PER_LINE ) {
        return -1; // failure
    }
    if( ofp != NULL) {
        fclose(ofp);
    }

    // Copy string into circular buffer
    strncpy( &(lineCircBuf[lineCircBuf_add][0]),
             str,
             MAX_CHARS_PER_LINE );
    lineCircBuf_add = ( lineCircBuf_add + 1 ) & lineCircBuf_mask;

    // Write to file
    ofp = fopen(FILENAME,"w");
    for( i = 0; i < MAX_ITEMS_IN_CIRCULARBUF-1; i++ ) {
        fprintf( ofp, "%s\n", lineCircBuf[i] );
    }
    fprintf( ofp, "%s", lineCircBuf[i] ); // do not add a newline to the last line b/c we only want N lines in the file

    return 0; // success
}

int removeLine(int index) {
    // not implemented yet
}

void unitTest() {
    int i;

    // Dummy text to demonstrate adding string lines
    char lines[5][MAX_CHARS_PER_LINE] = {
        "Hello world.",
        "Hello world AGAIN.",
        "The world is interesting so far!",
        "The world is not interesting anymore...",
        "Goodbye world."
    };

    // Add lines to circular buffer
    for( i = 0; i < sizeof(lines)/sizeof(lines[0]); i++ ) {
        addLine(&(lines[i][0]));
    }
}

int main() {
    unitTest();
    return 0;
}

Итак, в приведенном выше примере у нас было 5 строк ввода, а длина нашего буфера составляла всего 4 строки. Таким образом, вывод должен состоять только из 4 строк, и первая строка должна быть заменена последней строкой «Goodbye world». Конечно, первая строка вывода подтверждает, что действительно есть "Goodbye world":

Goodbye world.
Hello world AGAIN.
The world is interesting so far!
The world is not interesting anymore...
2
ответ дан 5 December 2019 в 06:10
поделиться

Просто создайте отображение файла требуемого размера (CreateFileMapping или mmap), запишите строки в буфер и начните заново, когда достигнуто максимальное количество.

1
ответ дан 5 December 2019 в 06:10
поделиться

, если файлы должны быть текстовыми:
Это очень проблематично при различной длине строк. Ваши первые две строки состоят из 80 символов каждая, как вы замените это строкой из 100 символов?

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

Если это необходимо для записи в журнал, используйте файлы журналов, например, один раз в день (как предлагает lassevek). Я сделал это еще проще: когда размер файла превышает предел, старый файл переименовывается в .bak (старый .bak удаляется) и запускается заново. При ограничении в 1 МБ это сохраняет, например, последний 1 МБ, но никогда не занимает больше 2 МБ.

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

если файл может быть в частном формате:
Используйте базовый механизм БД (например, SQLite, как предлагается) или другой механизм структурированного хранения.

1
ответ дан 5 December 2019 в 06:10
поделиться

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

1
ответ дан 5 December 2019 в 06:10
поделиться

Простое решение:

  • Определите максимальную длину 80 символов в строке. переносить более длинные «строки» в несколько строк.
  • Добавить заголовок строки к строке. например, «[# 589] Это 589-я строка», поэтому вы будете знать, что будет первым и т. д.
0
ответ дан 5 December 2019 в 06:10
поделиться

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

Я имею в виду, что вы можете просто вернуться к началу с помощью fseek () и уничтожьте более ранние данные, но я подозреваю, что это не то, что вам нужно.

0
ответ дан 5 December 2019 в 06:10
поделиться

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

0
ответ дан 5 December 2019 в 06:10
поделиться

Чтобы обойти проблему с переменным размером, вы, вероятно, получите косвенную схему и схему распределения. Он будет состоять из блока косвенного обращения с фиксированным количеством «указателей» в файл и одного указателя «следующего за записью», который будет обертываться вокруг N.

Но главный трюк будет заключаться в добавлении косвенное обращение.

0
ответ дан 5 December 2019 в 06:10
поделиться

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

logFile.lockForWrite();
currentPosition = logFile.getWritePosition();
logFile.seek(currentPosition);
for each line in lineBuffer {
    if ((currentPosition+line.length()) > logFile.getMaxSize()) {
        currentPosition = 0;
        logFile.seek(0);
    }
    logFile.write(line);
    currentPosition += line.length();
}
logFile.setWritePosition(currentPosition);
logFile.unlock();

Сложная часть состоит в том, чтобы поддерживать текущую позицию записи и находить способ координировать чтение файла (например, с помощью утилиты tail ), пока ваше приложение пишет в него. Утилита чтения должна также отслеживать позицию записи, поэтому цикл чтения выглядит следующим образом:

lastPosition = logFile.getWritePosition();
while (!killed) {
    logFile.wait();
    logFile.lockForRead();
    newPosition = logFile.getWritePosition();
    logFile.seek(lastPosition);
    newLine = logFile.readFrom(lastPosition, (newPosition-lastPosition));
    lastPosition = newPosition;
    logFile.unlock();
}

This isn ' t на каком-то конкретном языке - это просто псевдокод, но идея есть. Конечно, я оставил рассмотрение всех интересных крайних случаев читателю.

С учетом всего сказанного ... Я согласен с другими мнениями. Не делайте этого, если у вас нет действительно веской причины. Это звучит как отличная идея, но:

  • реализация трудно получить запись
  • еще труднее сделать эффективной
  • , поскольку позиция записи должна где-то сохраняться, несколько утилит имеют согласовать, как он читается, обновляется, инициализируется и т. д.
  • наличие нелинейного журнала затрудняет обработку журнала с использованием существующих инструментов, таких как grep , tail , perl и т. д.

В целом, вам будет лучше использовать какой-нибудь существующий пакет регистрации пакетов, который позволяет настраивать управление файлами журнала. Взгляните на Apache log4cxx или Poco's Poco :: Logger .

0
ответ дан 5 December 2019 в 06:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: