Verwenden einer C-Zeichenfolge wie einer Datei *

Lesezeit: 4 Minuten

Benutzer-Avatar
math4tots

Ich habe eine C-Funktion, die einen Stream von Zeichen aus a liest FILE*.

Wie könnte ich eine erstellen FILE* von einer Zeichenfolge in dieser Situation?

Bearbeiten:

Ich denke, mein ursprünglicher Beitrag war möglicherweise irreführend. Ich möchte eine erstellen FILE* aus einem Literal-String-Wert, sodass das Ergebnis FILE* würde sich so verhalten, als gäbe es wirklich irgendwo eine Datei, die den String enthält, ohne tatsächlich eine Datei zu erstellen.

Folgendes möchte ich tun:

void parse(FILE* f, Element* result);

int main(int argc, char** argv){
    FILE* f = mysteryFunc("hello world!");
    Element result;
    parse(f,&result);
}

  • Du meinst wie “FILE* file = fopen(“somefilename.txt”, “r”);”

    – selbe

    8. Juli 2012 um 8:20 Uhr

  • Die Standardbibliothek von C bietet diese Fähigkeit nicht.

    – Jerry Sarg

    8. Juli 2012 um 8:21 Uhr

Standard C bietet keine solche Einrichtung, aber POSIX definiert die fmemopen() Funktion, die genau das tut, was Sie wollen.

  • libcurl braucht ein FILE* und so habe ich diesen Trick verwendet, um a zu erstellen FILE* von einem std::string und dann erfolgreich aufgerufen curl_easy_setopt(curl_handle, CURLOPT_READDATA, file_pointer);.

    – Trevor Boyd Smith

    6. September 2018 um 15:29 Uhr


Benutzer-Avatar
David

Leider bietet die Standardbibliothek von C diese Funktionalität nicht; aber es gibt ein paar Möglichkeiten, es zu umgehen:

  • Erstellen Sie eine temporäre Datei, schreiben Sie Ihren String hinein und öffnen Sie sie dann zum Lesen. Wenn Sie POSIX haben, gettempnam wird einen eindeutigen Namen für Sie wählen

  • Die andere Option (wiederum nur für POSIX) ist to fork ein neuer Prozess, dessen Aufgabe es sein wird write die Saite zu einem Rohr, während Sie fdopen das andere Ende, um a zu erhalten FILE* für Ihre Funktion.

  • Wie @KeithThompson betonte, fmemopen macht genau das, was Sie wollen, also wenn Sie POSIX haben, verwenden Sie das. Auf jeder anderen Plattform (es sei denn, Sie können das Plattformäquivalent finden) benötigen Sie eine temporäre Datei.

Das letzte Mal, als ich diese Art von Problem hatte, habe ich tatsächlich eine Pipe erstellt, einen Thread gestartet und den Thread verwendet, um die Daten in die Pipe zu schreiben … Sie müssten sich jedoch mit Betriebssystemaufrufen befassen.

Es gibt wahrscheinlich andere Möglichkeiten, wie das Erstellen einer speicherabgebildeten Datei, aber ich suchte nach etwas, das einfach ohne viel Arbeit und Recherche funktionierte.

BEARBEITEN: Sie können das Problem natürlich in “Wie finde ich einen schönen temporären Dateinamen” ändern. Dann könnten Sie die Daten in eine Datei schreiben und wieder einlesen 🙂

pid_t pid;
int pipeIDs[2];

if (pipe (pipeIDs)) {
   fprintf (stderr, "ERROR, cannot create pipe.\n");
   return EXIT_FAILURE;
} 

pid = fork ();
if (pid == (pid_t) 0) {
   /* Write to PIPE in this THREAD  */

   FILE * file = fdopen( pipe[1], 'w');

   fprintf( file, "Hello world");
   return EXIT_SUCCESS;

} else if (pid < (pid_t) 0) {
  fprintf (stderr, "ERROR, cannot create thread.\n");
  return EXIT_FAILURE;
}


FILE* myFile = fdopen(pipe[0], 'r');

// DONE! You can read the string from myFile

....  .....

Vielleicht können Sie den Code ein wenig ändern, um ein benutzerdefiniertes Handle zu erhalten.

void parse(my_handle *h, Element *result)
{
  // read from handle and process
  // call h->read instead of fread
}

und definiert das Handle wie folgt:

struct my_handle
{
    // wrapper for fread or something
    int (*read)(struct my_handle *h, char *buffer, int readsize);
    // maybe some more methods you need
};

Implementieren Sie Ihren FILE*-Wrapper

struct my_file_handle
{
    struct my_handle base;
    FILE *fp;
};

int read_from_file(struct my_handle *h, char *buffer, int readsize)
{
    return fread(buffer, 1, readsize, ((my_file_handle*)h)->fp);
}

// function to init the FILE* wrapper
void init_my_file_handle(struct my_file_handle *h, FILE *fp)
{
    h->base.read = read_from_file;
    h->fp = fp;
}

Implementieren Sie nun Ihren String-Reader

struct my_string_handle
{
    struct my_handle base;
    // string buffer, size, and current position
    const char *buffer;
    int size;
    int position;
};

// string reader
int read_from_string(struct my_handle *h, char *buffer, int readsize)
{
    // implement it yourself. It's easy.
}

// create string reader handle
void init_my_string_handle(struct my_string_handle *h, const char *str, int strsize)
{
    // i think you know how to init it now.
}

//////////////////////////////////////////////////

Und jetzt können Sie einfach ein Handle an Ihre Parse-Funktion senden. Die Funktion kümmert sich nicht darum, woher die Daten kommen, sie kann sogar Daten aus dem Netzwerk lesen!

1279370cookie-checkVerwenden einer C-Zeichenfolge wie einer Datei *

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy