Можно ли использовать fseek() для вставки данных в середину файла? - С

Я знаю, что функцию fseek() можно использовать для вывода данных в определенное место в файле. Но мне было интересно, использую ли я fseek() для перемещения в середину файла, а затем вывожу данные. Будут ли новые данные перезаписывать старые данные? Например, если бы у меня был файл, содержащий 123456789, и я использовал fseek() для вывода новых данных после 5, файл бы содержал 12345newdata6789 или 12345newdata.


person John Vulconshinz    schedule 17.11.2012    source источник


Ответы (3)


Да, это позволяет вам это делать, и эти файлы называются «файлами произвольного доступа». Представьте, что у вас уже есть заданный файл (со структурой, но пустой), в этом случае вы можете заполнить нужные вам «слоты» или, если слот заполнен данными, вы можете перезаписать его.

typedef struct{
    int number;
    char name[ 20 ];
    char lastname[ 20 ];
    float score;
}students_t;

/* Supposing that you formatted the file already and the file is opened. */
/* Imagine the students are listed each one has a record. */

void modifyScore( FILE * fPtr ){
    students_t student = { 0, "", "", 0.0 };
    int nrecord;
    float nscore;

    printf( "Enter the number of the student:" );
    scanf( "%d", &record )
    printf( "Enter the new Score:" );
    scanf( "%f", &nscore ); // this is a seek example so I will not complicate things.

    /*Seek the file ( record - 1 ), because the file starts in position 0 but the list starts in 1*/
    fseek( fPtr, ( record  - 1  ) * sizeof ( students_t ), SEEK_SET );

    /* Now you can read and copy the slot */
    fread( fPtr, "%d%s%s%f", &student.number, student.name, student.lastname, &student.score );

    /* Seek again cause the pointer moved. */
    fseek( fPtr, ( record  - 1  ) * sizeof ( students_t ), SEEK_SET );
    student.score = nscore;

    /*Overwrite his information, only the score will be altered. */
    fwrite( &student, sizeof( student_t ), 1, fPtr );
}

Вот как это работает (изображение получено из Deitel-How to Program in C 6th Edition):

Deitel-Как программировать на языке C 6th Edition

person Alberto Bonsanto    schedule 17.11.2012
comment
@Bonsanto Должен ли я загружать весь файл в память, чтобы ваш метод работал? Цель, которую я пытаюсь достичь, - извлечь части файла в память (не весь файл), отредактировать их, а затем сохранить данные в файл без замены каких-либо данных, которые не были извлечены. - person John Vulconshinz; 18.11.2012
comment
Вам просто нужен отформатированный файл, скопируйте слот, который вы хотите отредактировать, используя обход в моем примере (переменная студента), измените нужный член, после этого снова выполните поиск, а затем перезапишите этот слот. - person Alberto Bonsanto; 18.11.2012
comment
@Bonstanto, во-первых, большое спасибо за вашу помощь. Но я новичок в C и немного смущен. Насколько я понимаю, вы ищете файл, пока не дойдете до той части, которую хотите отредактировать, затем извлеките ее в память как структуру, отредактируйте ее, а затем выведите обратно в то же место в файле. Я близко? Также будет ли этот метод работать, если новые данные превышают размер байтов старых данных? - person John Vulconshinz; 18.11.2012
comment
Вы очень близки, но если вы используете файлы с произвольным доступом, вы должны быть уверены, что ваша структура достаточно надежна, чтобы удерживать максимально допустимое значение. Вот связанный пост: stackoverflow .com/questions/13438941/ - person Alberto Bonsanto; 18.11.2012
comment
@Mawg Я извлек его из книги «Учись программировать на C» от ​​Deitel. Кстати, должны добавить кредиты - person Alberto Bonsanto; 13.09.2016
comment
Я просто надеялся найти новый инструмент для создания диаграмм :-) - person Mawg says reinstate Monica; 13.09.2016

Запись данных в «середину» файла приведет к перезаписи существующих данных. Таким образом, у вас будет «12345newdata».


РЕДАКТИРОВАТЬ: Как упоминалось в комментариях ниже, следует отметить, что это перезаписывает данные без усечения остальной части файла. В качестве расширенной версии вашего примера, если вы написали newdata после 5 в файле, содержащем 1234567890ABCDEFG, у вас будет 12345newdataCDEFG, не 12345newdata.

person Sidharth Mudgal    schedule 17.11.2012
comment
Он не усекает весь файл. Но он перезаписывает данные, уже присутствующие в позициях, в которые записываются. - person Sidharth Mudgal; 18.11.2012
comment
Ах, правда. В файле недостаточно данных, чтобы увидеть разницу. Извини. Я думаю, что это стоило бы упомянуть в ответе. - person rici; 18.11.2012

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

Вероятно, вы используете fwrite() или какую-либо другую функцию вывода, и они перезапишут, дав вам "12345newdata" вместо вставленного варианта.

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

Что-то вроде этого может быть достаточно:

insert(const void *ptr, size_t len, FILE *fp) {
    char tmp[len];
    size_t tmplen;

    while (len) {
        // save before overwriting
        tmplen = fread(tmp, 1, sizeof(tmp), fp);
        fseek(fp, -tmplen, SEEK_CUR);

        // overwrite
        fwrite(ptr, len, 1, fp);

        // reloop to output saved data
        ptr = tmp;
        len = tmplen;
    }
}

(Обработка ошибок на fread() и fwrite() опущена для многословия.)

person antak    schedule 18.11.2012
comment
Антак, спасибо за ответ, и это решение будет работать, но я хочу вставить новые данные без буферизации старых данных, которые будут перезаписаны. Я знаю, что это кажется ненужным ограничением, но проблема, над которой я работаю, требует редактирования больших файлов. Что было бы обременительно удержать в памяти. - person John Vulconshinz; 18.11.2012
comment
Вам не нужно буферизировать весь файл. FWIW, в приведенном выше примере используется только буфер того же объема, что и данные, которые вы выводите (и никак не зависит от размера фактического файла). - person antak; 19.11.2012