Заменить строку в текстовом файле, используя C - PullRequest
3 голосов
/ 12 октября 2011

Я хочу изменить строки, содержащие символ # в текстовом файле, с помощью heet, используя C.

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

Есть ли какой-нибудь другой трюк для удаления или удаления целой строки из файла?Таким образом, мы можем легко заменить его.

myfile.txt: (до исполнения)

Joy
#Smith
Lee
Sara#
Priyanka
#Addy

Код:

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

int main() {
    FILE *pFile;
    fpos_t pos1, pos2;
    int line = 0;
    char buf[68]
    char *p;
    char temp[10] = "heet";

    pFile = fopen("myfile.txt", "r+");

    printf("changes are made in this lines:\t");    
    while (!feof(pFile)) {
        ++line;
        fgetpos(pFile, &pos1);          

        if (fgets(buf, 68, pFile) == NULL)  
            break;

        fgetpos(pFile, &pos2);

        p = strchr(buf, '#');

        if (p != NULL) {
            printf("%d, " , line);
            fsetpos(pFile, &pos1);  
            fputs(temp, pFile);
        }
        fsetpos(pFile, &pos2);
    }

    fclose(pFile);
    return 0;
}

myfile.txt: (после выполнения)

Joy  
heetth  
Lee  
heet#  
Priyanka  
heety  

Вывод:

changes are made in this lines: 2, 4, 6,  

myfile.txt: (хочу получить)

Joy  
heet  
Lee  
heet  
Priyanka  
heet  

Ответы [ 4 ]

6 голосов
/ 12 октября 2011

Лучший способ сделать то, что вы хотите, это использовать утилиту вроде sed. Это быстрее и использует меньше памяти, чем то, что вы (или я) написали бы.

Помимо этого, давайте предположим, что вы все равно хотите написать и написать сами.

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

Следующий псевдокод иллюстрирует простой подход:

open original file
open output file
allocate a line buffer that is large enough
read a line from the original file
do
  return an error if the buffer is too small
  manipulate the line
  write the manipulated line to the output file
  read a line from the original file
loop until read returns nothing

sed делает это намного умнее. Однажды я увидел объяснение того, как работает sed, но моя карма Google не может его найти.

Изменить: Как это сделать с помощью sed:

 sed -e 's/.*\#.*/heet/g' myfile.txt

Команда s или замена sed может заменить одну строку или регулярное выражение другой строкой.

Приведенная выше команда интерпретируется как:

заменить любую строку, в которой где-то есть #, на heet. Последний g говорит sed сделать это глобально, то есть во всем файле.

Edit2: По умолчанию sed записывает в стандартный вывод. Чтобы переписать файл, вы должны перенаправить вывод в файл, а затем переименовать его. В linux выполните следующее (вы можете запустить командную строку из C с помощью system):

sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt
rm myfile.txt
mv temp_file123.txt myfile.txt

Из C:

system("sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt");
system("rm myfile.txt");
system("mv temp_file123.txt myfile.txt");

Если вы хотите сделать это всего одним вызовом system, поместите все содержимое командной строки в сценарий оболочки.

1 голос
/ 12 октября 2011

Вы, вероятно, должны рассматривать ввод / вывод как утилиту UNIX и заменять строку, читая весь ввод и записывая весь вывод, как sed или что-то в этом роде. Будет труднее редактировать строку на месте, так как вам нужно сдвинуть следующий текст «вниз», чтобы заставить его работать.

0 голосов
/ 26 августа 2018

Вы не можете достичь своей цели, переписав файл на месте, как в коде, потому что heet на 3 байта длиннее #, и нет стандартной функции для вставки байтов в середину файла.

Обратите внимание также на эти важные вопросы:

  • вы не проверяете, удалось ли fopen() открыть файл. У вас неопределенное поведение, если файл не существует или не может быть открыт для режима чтения + обновления.
  • while (!feof(pFile)) не останавливается точно в конце файла, поскольку индикатор конца файла, возвращаемый feof(), устанавливается только в случае сбоя операции чтения, а не раньше. Вместо этого вы должны написать:

        while (fgets(buf, 68, pFile) != NULL) {
    
  • если в файле есть строки длиннее 66 символов, номера строк будут вычислены неправильно.

Существует 2 способа замены текста в файле:

  • вы можете создать временный файл и записать в него измененное содержимое. Как только все содержимое будет преобразовано, удалите исходный файл с помощью remove() и переименуйте временный файл в исходное имя с помощью rename(). Этот метод использует дополнительное пространство на устройстве хранения и требует, чтобы вы могли создать новый файл и определить имя файла, которое не конфликтует с существующими именами файлов.
  • поочередно, вы можете прочитать полное содержимое исходного файла и перезаписать его измененным содержимым с самого начала. Это работает, потому что измененное содержимое длиннее исходного. Этот метод может не работать, если файл очень большой и не помещается в памяти, что довольно редко встречается сегодня для обычных текстовых файлов.

Вот модифицированная версия, использующая второй подход:

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

int main() {
    FILE *pFile;
    int c, line, changes;
    unsigned char *buf;
    size_t pos, length, size;
    char replacement[] = "heet";

    /* open the file */
    pFile = fopen("myfile.txt", "r+");
    if (pFile == NULL) {
        printf("cannot open myfile.txt\n");
        return 1;
    }

    /* read the file */
    buf = NULL;
    length = size = 0;
    while ((c = getc(pFile)) != EOF) {
        if (length == size) {
            size = size + size / 2 + 128;
            buf = realloc(buf, size);
            if (buf == NULL) {
                printf("not enough memory to read myfile.txt\n");
                fclose(pFile);
                return 1;
            }
        }
        buf[length++] = c;
    }
    /* write the modified contents */
    rewind(pFile);
    line = 1;
    changes = 0;
    for (pos = 0; pos < length; pos++) {
        c = buf[pos];
        if (c == '\n')
            line++;
        if (c == '#') {
            if (changes++ == 0)
                printf("changes are made in this lines:\t");
            else
                printf(", ");
            printf("%d", line);
            fputs(replacement, pFile);
        } else {
            putc(c, pFile);
        }
    }
    free(buf);
    fclose(pFile);
    if (changes == 0)
        printf("no changes were made\n");
    else
        printf("\n");
    return 0;
}
0 голосов
/ 25 августа 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...