Können Ausgaberoutinen, die eine Zeichenfolge bauen in C verwendet werden, um einen FILE * drucken?

StackOverflow https://stackoverflow.com/questions/1270212

  •  13-09-2019
  •  | 
  •  

Frage

Ich habe ein schlechtes Gefühl, dass die Antwort auf diese Frage „nein“ ist, aber ich wollte das es für den Fall, jemand werfen hat keine cleveren Ideen.

Ich habe eine Reihe von Ausgaberoutinen, die eine komplexe Datenstruktur nehmen und es in einem Textformat drucken. Sie haben Prototypen wie:

void print_mystruct(struct mystruct *s, FILE *stream)

Ich schrieb es auf diese Weise, so dass ich effizient zu bekommen, gepufferte Ausgabe an das Endgerät, in eine Datei mit dem Netzwerk, etc.

Leider gibt es keine Möglichkeit, die ich kenne, Standard C99 mit, dass ich die gleichen Routinen verwenden, um eine Zeichenfolge im Speicher aufzubauen.

Also meine Fragen sind:

  1. gibt es eine clevere Art und Weise, dass ich effizient fputs verwenden kann (), fprintf () usw. zur Ausgabe in einen String?
  2. wenn nicht, ist es ein besseres Paradigma, das sowohl gepufferte Dateiausgabe und String-Gebäude effizient tun können? Das Beste, was ich denken kann, ist meine eigene Struktur mit einer V-Tabelle haben (anstelle eines FILE *). Die VTable würde eine Ausgabefunktion haben, die entweder auf einen String anhängen oder rufen würde Fwrite. Aber dann würde ich auch printf-Wrapper erstellen haben.

Alle anderen cleveren Ideen?

EDIT: Ich habe entdeckt, dass fmemopen() Teil POSIX.1-2008 ist (siehe: fmemopen () ), ist aber nicht weit unterstützt, zumindest nach dem GNU libc manpage.

War es hilfreich?

Lösung

Es gibt keinen portablen Weg, dies zu tun. glibc-Systeme (Linux) Gibt open_memstream / fmemopen , könnten andere Systeme nicht etwas Vergleichbares.

Der tragbare Weg ist, um eine Datei zu schreiben und es zurück in einen String zu lesen. Oder die Bedenken zu trennen. Statt der Durchführung

void print_mystruct(struct mystruct *s,FILE *f);

Sie würden zum Beispiel implementieren

char *mystruct_2_str(struct mystruct *s);

, die dynamisch eine Zeichenfolge zuordnet (oder in einem Puffer übergeben), formatiert sie in einen String mit Standard-String-Funktionen (snprintf etc.) und haben die Anrufer entscheiden, ob das schreiben in eine Datei *

Andere Tipps

Wenn Sie nicht über die Suche nach auf der Datei kümmern, gibt es eine portable (zu allen früheren POSIX Zielen) Weg, um die gleiche Wirkung wie fmemopen zu bekommen, aber es ist ziemlich teuer. Machen Sie ein Rohr und ein neues, frei stehenden Gewinde und fdopen das Schreibende des Rohres in dem aufrufenden Thread. Der neue Thread liest dann von dem Leseende des Rohres und legt die Daten in den Stringpuffer. Haben Sie den neuen Thread Rückkehr, wenn es EOF aus dem Rohr wird; da sie losgelöst ist, gibt es keine Bereinigungs zu tun.

Sicher, es gibt nichts Magisches über die Datei-Struktur, obwohl ich weiß nicht, von jedem in der Bibliothek Funktion baute man aus einem String-Puffer zu erstellen. Hier ist mindestens eine Version der Definition.

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

Sie können eine dieser Strukturen auf eigene Faust aus einem String-Puffer herzustellen und an Ihre Funktion übergeben, und auch eine tear-down-Funktion erstellen, die den Speicher freigibt.

Die Frage ist, die CRT-Bibliothek Anrufe können Sie auf Ihre Version verwenden? Offensichtlich etwas an den Dateinamen beziehen wird fehlschlagen, da es nicht ein. Aber Sie könnten wahrscheinlich Funktionen wie fwrite und fread und fseek, die die Zeiger werden Manipulation und mehr Raum bei Bedarf zugewiesen werden.

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

char* file_to_string(FILE *f, int *len) {
  if (fseek(f, 0, SEEK_END)) handle_error();
  int buflen = ftell(f);
  if (len) *len = buflen;
  char *buf = malloc(buflen + 1);
  buf[buflen] = '\0';
  rewind(f);
  size_t readlen = fread(buf, 1, buflen, f);
  if (readlen != buflen) handle_error();
  // in particular, note readlen might not equal buflen in the face of text-mode
  // conversions, but tmpfile() indicates binary-mode, so doesn't affect this
  // case
  return buf;
}

int main() {
  FILE *temp = tmpfile();

  // use FILE interface
  fputs("written to temporary file\n", temp);

  char *s = file_to_string(temp, NULL);
  // now you have contents as a string
  free(s);

  // can also rewind the FILE and process it incrementally, etc.

  return 0;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top