Чтение из файла слово за словом

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

%list% name1 name2 name3 %list%

%dirs% archive directories %dirs%

%content% name1 path1 content of file1 %content%
%content% name2 path2 content of file2 %content%
%content% name3 path3 content of file3 %content%

%list% содержит имена файлов в архиве
%dirs% содержит имена каталогов
%content% перечисляет содержимое файлов.

Поскольку мне нужно распечатать содержимое указанного файла, я хочу прочитать этот архив слово за словом, чтобы определить %content%tag и имя файла.
Я знаю о существовании fscanf(), но, похоже, он работает эффективно, только если вы знать шаблон архива.

Есть ли библиотека или команда C, например ifstream для C++, которая позволяет мне читать слово за словом?

Спасибо


person Andrea Gottardi    schedule 06.05.2013    source источник
comment
Как насчет fgets и strtok?   -  person Some programmer dude    schedule 06.05.2013
comment
Может стоит показать свой fscanf код и рассказать, что в нем не так... Сейчас непонятно, что в нем такого неэффективного.   -  person hyde    schedule 06.05.2013
comment
Самый простой способ сделать это — использовать fgetc, пока не появится символ пробела (например, \r \n \t или пробел). Затем проанализируйте слово, которое вы только что прочитали. Без дополнительной информации трудно помочь дальше.   -  person RageD    schedule 06.05.2013
comment
Вы можете читать слово за словом, используя fscanf (хотя fgets может быть проще). Однако, как бы мне не хотелось это предлагать, вы можете захотеть реструктурировать свой архив с помощью XML и использовать существующие библиотеки XML (expat, libxml и т. д.) для доступа к нему и его изменения. Таким образом, вам не нужно беспокоиться о разборе тегов, только о содержании.   -  person John Bode    schedule 06.05.2013
comment
@JohnBode, говорить кому-то, кто не может прочитать слово из файла, использовать XML, вероятно, не очень хорошая идея.   -  person Shahbaz    schedule 06.05.2013
comment
@Shahbaz: именно поэтому я ненавидел это предлагать. Тем не менее, структура их архива убедительно свидетельствует в пользу этого, и с приличным XML API (для достаточно расплывчатых определений приличия) им не придется беспокоиться о размерах буферов, парсинге тегов или других низкоуровневых проблемах, которые не нужны. это обязательно трудно, но, тем не менее, заноза в заднице.   -  person John Bode    schedule 06.05.2013
comment
этот архив не для рабочих целей. Я хотел отредактировать команду tar, но это было слишком грязно для моих знаний C. Таким образом, я попытался сделать (возможно, чересчур) простой архив.   -  person Andrea Gottardi    schedule 07.05.2013


Ответы (2)


Вы можете просто использовать fscanf для чтения по одному слову за раз:

void read_words (FILE *f) {
    char x[1024];
    /* assumes no word exceeds length of 1023 */
    while (fscanf(f, " %1023s", x) == 1) {
        puts(x);
    }
}

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

person jxh    schedule 06.05.2013
comment
Если он не может гарантировать, что его буфер достаточно велик, %s может быть опасен. Возможно %1024s, но это, возможно, ограничило бы функциональность. - person RageD; 06.05.2013
comment
@RageD: я обновил ответ. - person jxh; 06.05.2013
comment
NB: Вы должны указать "%1023s" для буфера размером 1024. Длина в строке формата не включает терминальный нуль. (Почему? Древняя история — как минимум на 30 лет уже поздно, чтобы изменить ее сейчас.) - person Jonathan Leffler; 06.05.2013
comment
+1 за обновленную ссылку. @JonathanLeffler: Это правильно, спасибо (ба, по одному) - person RageD; 06.05.2013
comment
@JonathanLeffler: Также упущение заключается в том, что нет другого способа ввести вычисленную границу для строки, кроме динамического создания строки во время выполнения (вместо этого * используется для ignore). - person jxh; 10.05.2018

нравится

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

typedef char Type;

typedef struct vector {
    size_t size;
    size_t capacity;
    Type *array;
} Vector;

Vector *vec_make(){
    Vector *v;
    v = (Vector*)malloc(sizeof(Vector));
    if(v){
        v->size = 0;
        v->capacity=16;
        v->array=(Type*)realloc(NULL, sizeof(Type)*(v->capacity += 16));
    }
    return v;
}

void vec_add(Vector *v, Type value){
    v->array[v->size] = value;
    if(++v->size == v->capacity){
        v->array=(Type*)realloc(v->array, sizeof(Type)*(v->capacity += 16));
        if(!v->array){
            perror("memory not enough");
            exit(-1);
        }
    }
}

void vec_reset(Vector *v){
    v->size = 0;
}

size_t vec_size(Vector *v){
    return v->size;
}

Type *vec_getArray(Vector *v){
    return v->array;
}

void vec_free(Vector *v){
    free(v->array);
    free(v);
}

char *fin(FILE *fp){
    static Vector *v = NULL;
    int ch;

    if(v == NULL) v = vec_make();
    vec_reset(v);
    while(EOF!=(ch=fgetc(fp))){
        if(isspace(ch)) continue;//skip space character
        while(!isspace(ch)){
            vec_add(v, ch);
            if(EOF == (ch = fgetc(fp)))break;
        }
        vec_add(v, '\0');
        break;
    }
    if(vec_size(v) != 0) return vec_getArray(v);
    vec_free(v);
    v = NULL;
    return NULL;
}

int main(void){
    FILE *fp = stdin;
    char *wordp;
    while(NULL!=(wordp=fin(fp))){
        printf("%s\n", wordp);
    }
    return 0;
}
person BLUEPIXY    schedule 06.05.2013