2009-11-16 11 views
5

Poszukuję sposobu przekazania w postaci FILE * dla niektórych funkcji, aby funkcja mogła do niej pisać za pomocą fprintf. Jest to łatwe, jeśli chcę, aby dane wyjściowe pojawiały się w rzeczywistym pliku na dysku, powiedzmy. Ale zamiast tego chciałbym uzyskać wszystkie dane wyjściowe w postaci ciągu znaków (char *). Rodzaj API Chciałbym to:Tworzenie strumienia FILE *, który powoduje ciąg znaków

/** Create a FILE object that will direct writes into an in-memory buffer. */ 
FILE *open_string_buffer(void); 

/** Get the combined string contents of a FILE created with open_string_buffer 
    (result will be allocated using malloc). */ 
char *get_string_buffer(FILE *buf); 

/* Sample usage. */ 
FILE *buf; 
buf = open_string_buffer(); 
do_some_stuff(buf); /* do_some_stuff will use fprintf to write to buf */ 
char *str = get_string_buffer(buf); 
fclose(buf); 
free(str); 

glibc nagłówki wydają się wskazywać, że plik można skonfigurować funkcje hakowych przeprowadzić rzeczywistą czytania i pisania. W moim przypadku myślę, że chcę, aby hak do zapisu dołączał kopię ciągu do połączonej listy, i aby istniała funkcja get_string_buffer, która oblicza całkowitą długość listy, przydziela jej pamięć, a następnie kopiuje każdy element do niego we właściwym miejscu.

Dążę do czegoś, co może być przekazane do funkcji, takiej jak do_some_stuff, bez tej funkcji, która musi znać cokolwiek poza tym, że ma do niej dostęp FILE *.

Czy istnieje jakieś wdrożenie czegoś takiego? Wydaje się, że jest to użyteczne i przyjazne dla C - zakładając, że mam rację co do możliwości rozszerzenia o FILE.

Odpowiedz

5

Jeśli przenoszenie nie jest ważne dla ciebie, możesz spojrzeć na fmemopen i open_memstream. Są rozszerzeniami GNU, dlatego są dostępne tylko w systemach glibc. Chociaż wygląda na to, że są częścią POSIX.1-2008 (fmemopen i open_memstream).

+0

open_memstream jest dokładnie tym, czego chcę. Nie jestem pewien, czy używa on podejścia z listą odsyłaczy, ale nie będę pisał do niego dużych kwot, więc nie ma to znaczenia. – Edmund

2

Nie jestem pewien, czy to możliwe, aby nie przenośnie przedłużyć FILE przedmiotów, ale jeśli szukasz czegoś nieco bardziej przyjazny POSIX, można użyć pipe i fdopen.

To nie jest dokładnie to samo, co ma, który zwraca bajty z bufora, ale z pewnością jest to FILE* z programowo określonymi treściami.

int fd[2]; 
FILE *in_pipe; 

if (pipe(fd)) 
{ 
    /* TODO: handle error */ 
} 

in_pipe = fdopen(fd[0], "r"); 
if (!in_pipe) 
{ 
    /* TODO: handle error */ 
} 

Stamtąd chcesz napisać swój bufor do fd[1] użyciu write(). Ostrożnie z tym krokiem, ponieważ write() może zablokować, jeśli bufor rury jest pełny (tj. Ktoś musi przeczytać drugi koniec), a możesz otrzymać EINTR, jeśli twój proces otrzyma sygnał podczas pisania. Uważaj też na SIGPIPE, co ma miejsce, gdy drugi koniec zamyka rurę. Może dla twojego użytku możesz zrobić write bufora w osobnym wątku, aby uniknąć blokowania i upewnij się, że obsługujesz SIGPIPE.

Oczywiście, to nie stworzy możliwy do przeszukania FILE* ...

+0

+1 dobre wyjaśnienie na temat potrzeba osobnego wątku – Andomar

0

Nie jestem pewien, czy rozumiem, dlaczego chcesz zepsuć PLIK *. Nie możesz po prostu napisać do pliku, a następnie załadować go w łańcuchu?

char *get_file_in_buf(char *filename) { 
    char *buffer; 
    ... get file size with fseek or fstat ... 
    ... allocate buffer ... 
    ... read buffer from file ... 
    return buffer; 
} 

Jeśli chcesz tylko „write” sformatowany tekst w ciąg, innym rozwiązaniem mogłoby być obsłużyć bufor rozszerzalnej za pomocą snprintf() (patrz odpowiedź na to SO pytanie do sugestii, w jaki sposób sobie z tym poradzić: Resuming [vf]?nprintf after reaching the limit).

Jeśli natomiast chcesz utworzyć typ, który może być przekazywany w sposób przejrzysty do dowolnej funkcji robienia FILE * do ich występowania w buforach smyczkowych, jest to o wiele bardziej skomplikowana sprawa ...

+0

Istnieją dobre powody, aby chcieć takiego "PLIKU": Istnieje wiele bibliotek, które oferują tylko oparte na 'FILE *' I/O i nalegają na odczytanie pliku, kiedy dane mogą być już dostępne w pamięci. Pożądane jest zatem, aby móc przekazywać bufor pamięci zamiast zapisywać do pliku tylko dla tych bibliotek. Niestety, te biblioteki rzadko, jeśli w ogóle, oferują alternatywę dla ich zależnego API "FILE *". – greyfade

Powiązane problemy