2012-01-27 2 views
15

Я написал программу, которая берет файл в качестве ввода и всякий раз, когда он находит строку длиной> 80, она добавляет \ и \ n к этому файл, чтобы сделать его 80 символов в ширину макс.Функция C для вставки текста в определенном месте в файле без перезаписи существующего текста

Проблема заключается в том, что я использовал fseek для вставки \ и \ n всякий раз, когда длина превышает 80, поэтому она переопределяет два символа этой строки, которая превышает длину 80. Есть ли способ, с помощью которого я могу вставлять текст без переопределения существующий текст?

Вот мой код: -

#include<stdio.h> 
#include<string.h> 

int main(int argc, char *argv[]) 
{ 
    FILE *fp1,*fp2; 
    int prev=0,now=0; 
    char ch; 
    int flag=0; 
    long cur; 
    fp1=fopen(argv[1],"r+"); 
    if(fp1==NULL){ 
    printf("Unable to open the file to read. Program will exit."); 
    exit(0); 
    } 
    else{ 
    while((ch=fgetc(fp1))!=EOF){ 
     if(ch!=' ' && ch!='\n'){ 
     now=now+1; 
     } 
     else{ 
     if(now>=80){ 
      fseek(fp1,cur,SEEK_SET); 
      fputc('\\',fp1); 
      fputc('\n',fp1); 
      now=0; 
      continue; 
     } 
     if(ch=='\n'){ 
      flag=0; 
      now=0; 
      continue; 
      } 
     else{ 
      prev=now; 
      cur=ftell(fp1); 
     } 
     now=now+1; 
     } 
    } 
    } 
    fclose(fp1); 
    return 0; 
} 

Чтобы запустить его, вам нужно сделать следующее: -

[email protected]$ cc xyz.c 
[email protected]$ ./a.out file_to_check.txt 
+2

Нет, нет способ вставки данных в t он посередине файла. Вам нужно обработать «переключение» данных самостоятельно и/или записать в новый файл. – Mat

+1

@Mat: Я бы отметил ваш комментарий как «Не комментарий», так как это ответ :) –

+2

Возможный дубликат [Как вставлять и удалять некоторые символы в середине файла?] (Http: // stackoverflow. com/questions/2431073/how-do-i-insert-and-delete-some-characters-in-the-the-a-file) – Mat

ответ

7

Нет, невозможно вставить символы в существующий файл. Для этого вам понадобится второй файл.

+1

Это не совсем верно. Вы можете снова искать(), fread(), seek() и fwrite(). Конечно, хвост должен вписываться в память. – ckruse

+1

@ckruse: Это, и вы также рискуете уничтожить исходный файл, если 'fwrite()' не заполняется по какой-либо причине. Поэтому я не считаю этот подход приемлемым решением. – NPE

+0

Вы меня убедили. – ckruse

2

Нет, нет никакой возможности. Вам необходимо создать новый файл или переместить содержимое файла на 2 символа назад.

0

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

16

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

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

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

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

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

TL; DR версия:

Когда вы цените ваши данные, не уничтожить его, прежде чем у вас есть замещающие данные готовы.

1

Это функция я использую для такого рода вещи:

int finsert (FILE* file, const char *buffer) { 

    long int insert_pos = ftell(file); 
    if (insert_pos < 0) return insert_pos; 

    // Grow from the bottom 
    int seek_ret = fseek(file, 0, SEEK_END); 
    if (seek_ret) return seek_ret; 
    long int total_left_to_move = ftell(file); 
    if (total_left_to_move < 0) return total_left_to_move; 

    char move_buffer[1024]; 
    long int ammount_to_grow = strlen(buffer); 
    if (ammount_to_grow >= sizeof(move_buffer)) return -1; 

    total_left_to_move -= insert_pos; 

    for(;;) { 
     u16 ammount_to_move = sizeof(move_buffer); 
     if (total_left_to_move < ammount_to_move) ammount_to_move = total_left_to_move; 

     long int read_pos = insert_pos + total_left_to_move - ammount_to_move; 

     seek_ret = fseek(file, read_pos, SEEK_SET); 
     if (seek_ret) return seek_ret; 
     fread(move_buffer, ammount_to_move, 1, file); 
     if (ferror(file)) return ferror(file); 

     seek_ret = fseek(file, read_pos + ammount_to_grow, SEEK_SET); 
     if (seek_ret) return seek_ret; 
     fwrite(move_buffer, ammount_to_move, 1, file); 
     if (ferror(file)) return ferror(file); 

     total_left_to_move -= ammount_to_move; 

     if (!total_left_to_move) break; 

    } 

    seek_ret = fseek(file, insert_pos, SEEK_SET); 
    if (seek_ret) return seek_ret; 
    fwrite(buffer, ammount_to_grow, 1, file); 
    if (ferror(file)) return ferror(file); 

    return 0; 
} 

Используйте это так:

FILE * file= fopen("test.data", "r+"); 
ASSERT(file); 

const char *to_insert = "INSERT"; 

fseek(file, 3, SEEK_SET); 
finsert(file, to_insert); 

ASSERT(ferror(file) == 0); 
fclose(file); 

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

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