Вопрос Обработки Файла на C программировании - PullRequest
2 голосов
/ 11 апреля 2009

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

Так что я использую fscanf (fptr, "% s", words), чтобы прочитать слово, и оно должно прекратиться, как только оно встретит конец строки ...

но это не возможно в fscanf, я думаю ... поэтому, пожалуйста, скажите мне, что делать ...

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

Ответы [ 4 ]

9 голосов
/ 11 апреля 2009

Используйте fgets () . Да, ссылка на cplusplus, но она исходит от c stdio.h.

Вы также можете использовать sscanf() для чтения слов из строки или просто strtok() для их разделения.


В ответ на комментарий: это поведение fgets() (оставляя \n в строке) позволяет вам определить, был ли встречен фактический конец строки. Обратите внимание, что fgets() может также читать только часть строки из файла, если предоставленный буфер недостаточно велик. В вашем случае - просто проверьте \n в конце и удалите его, если он вам не нужен. Примерно так:

// actually you'll get str contents from fgets()
char str[MAX_LEN] = "hello there\n";
size_t len = strlen(str);
if (len && str[len-1] == '\n') {
    str[len-1] = 0;
}

Просто так.

3 голосов
/ 11 апреля 2009

Если вы работаете в системе с доступными расширениями GNU, есть что-то, называемое getline (man 3 getline), которое позволяет вам читать файл построчно, в то время как getline выделит вам дополнительную память при необходимости. Страница man содержит пример, который я изменил, чтобы разделить строку, используя strtok (man 3 strtrok).

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

int main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
    {
        printf("File open failed\n");
        return 0;
    }

    while ((read = getline(&line, &len, fp)) != -1) {
        // At this point we have a line held within 'line'
        printf("Line: %s", line);
        const char * delim = " \n";
        char * ptr; 
        ptr = (char * )strtok(line,delim);

        while(ptr != NULL)
        {
            printf("Word: %s\n",ptr);
            ptr = (char *) strtok(NULL,delim);
        }
    }

    if (line)
    {
        free(line);
    }
    return 0;
}
2 голосов
/ 11 апреля 2009

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

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

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

Редактировать: Чтобы иметь контроль над буфером во входном потоке, вам может понадобиться вызвать setbuf () или setvbuf (), чтобы принудительно переключить его в буферный режим. Если входной поток заканчивается небуферизованным, то использование явного буфера некоторой формы всегда будет быстрее, чем getc () в необработанном потоке.

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

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

1 голос
/ 11 апреля 2009

но это невозможно в fscanf,

Да, с небольшим количеством зла;)

Обновление: больше разъяснений о зле

но, к сожалению, немного не так. Я предполагаю, что [^\n]%*[^\n] должен читать [^\n]%*. Кроме того, следует отметить, что этот подход удалит пробелы с линий. - стрекоза

Обратите внимание, что xstr(MAXLINE) [^\n] читает MAXLINE символов, которые могут быть чем угодно, кроме символа новой строки (т.е. \n). Вторая часть спецификатора, т. Е. *[^\n], отклоняет все (поэтому есть символ *), если строка содержит более MAXLINE символов, но NOT , включая символ новой строки. Символ новой строки говорит scanf прекратить сопоставление. Что если мы сделаем так, как предлагает Стрекоза? Единственная проблема в том, что scanf не будет знать, где остановиться, и будет продолжать подавлять назначение до тех пор, пока не будет достигнут следующий символ новой строки (что является другим совпадением для первой части). Следовательно, вы будете следовать за одной строкой ввода при составлении отчета.

Что если вы хотите читать в цикле? Небольшая модификация требуется. Нам нужно добавить getchar(), чтобы использовать непревзойденный перевод строки. Вот код:

#include <stdio.h>

#define MAXLINE 255

/* stringify macros: these work only in pairs, so keep both */
#define str(x) #x
#define xstr(x) str(x)

int main() {
    char line[ MAXLINE + 1 ];
    /* 
       Wickedness explained: we read from `stdin` to `line`.
       The format specifier is the only tricky part: We don't
       bite off more than we can chew -- hence the specification 
       of maximum number of chars i.e. MAXLINE. However, this
       width has to go into a string, so we stringify it using  
       macros. The careful reader will observe that once we have
       read MAXLINE characters we discard the rest upto and
       including a newline.
     */
    int n = fscanf(stdin, "%" xstr(MAXLINE) "[^\n]%*[^\n]", line);
    if (!feof(stdin)) {
        getchar();
    }
    while (n == 1) {
        printf("[line:] %s\n", line);
        n = fscanf(stdin, "%" xstr(MAXLINE) "[^\n]%*[^\n]", line);
        if (!feof(stdin)) {
            getchar();
        }
    } 
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...