问题
I have a C function that reads a stream of characters from a FILE*
.
How might I create a FILE*
from a string in this situation?
Edit:
I think my original post may have been misleading. I want to create a FILE*
from a literal string value, so that the resulting FILE*
would behave as though there really was a file somewhere that contains the string without actually creating a file.
The following is what I would like to do:
void parse(FILE* f, Element* result);
int main(int argc, char** argv){
FILE* f = mysteryFunc("hello world!");
Element result;
parse(f,&result);
}
回答1:
Standard C provides no such facility, but POSIX defines the fmemopen() function that does exactly what you want.
回答2:
Unfortunately, C's standard library doesn't provide this functionality; but there are a few ways to get around it:
Create a temporary file, write your string to it, then open it for reading. If you've got POSIX,
gettempnam
will choose a unique name for youThe other option (again for POSIX only) is to
fork
a new process, whose job will be towrite
the string to a pipe, while youfdopen
the other end to obtain aFILE*
for your function.As @KeithThompson pointed out,
fmemopen
does exactily what you want, so if you have POSIX, use that. On any other platform, (unless you can find the platform-equivalent), you'll need a temporary file.
回答3:
Last time I had this kind of problem I actually created a pipe, launched a thread, and used the thread to write the data into the pipe... you would have to look into operating system calls, though.
There are probably other ways, like creating a memory mapped file, but I was looking for something that just worked without a lot of work and research.
EDIT: you can, of course, change the problem to "how do I find a nice temporary filename". Then you could write the data to a file, and read it back in :-)
回答4:
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
.... .....
回答5:
Maybe you can change the code a little bit to receive a custom handle.
void parse(my_handle *h, Element *result)
{
// read from handle and process
// call h->read instead of fread
}
and defines the handle like this:
struct my_handle
{
// wrapper for fread or something
int (*read)(struct my_handle *h, char *buffer, int readsize);
// maybe some more methods you need
};
implement your 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;
}
Now, implement your 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.
}
//////////////////////////////////////////////////
And now, you can simply send a handle to your parse function. The function doesn't care where the data comes from, it can even read data from network!
来源:https://stackoverflow.com/questions/11381694/using-a-c-string-like-a-file