17

If I have a buffer which contains the data of a file, how can I get a file descriptor from it? This is a question derived from how to untar file in memory

3 Answers 3

17

I wrote a simple example how to make filedescriptor to a memory area:

#include <unistd.h> #include <stdio.h> #include <string.h> char buff[]="qwer\nasdf\n"; int main(){ int p[2]; pipe(p); if( !fork() ){ for( int buffsize=strlen(buff), len=0; buffsize>len; ) len+=write( p[1], buff+len, buffsize-len ); return 0; } close(p[1]); FILE *f = fdopen( p[0], "r" ); char buff[100]; while( fgets(buff,100,f) ){ printf("from child: '%s'\n", buff ); } puts(""); } 
Sign up to request clarification or add additional context in comments.

7 Comments

On Linux, vmsplice() might be useful: it avoids the need for a for-loop to write data to the pipe.
This is a pretty awesome solution, but if you need to be able to do more than read from the fd (i.e. seek), then this won't work. You cannot seek on a pipe (at least not on the platforms I use).
Why didn't you choose fmemopen()? Yes, it's POSIX and not C, but pipe() is also POSIX, isn't it?
@Mecki it appears from the man pages that fileno() will return -1 when called on a FILE* returned from fmemopen().
Just to provide a citation for @tekknolagi's comment, man fmemopen says "There is no file descriptor associated with the file stream returned by this function (i.e., fileno(3) will return an error if called on the returned stream)." It doesn't say why it doesn't work, though. I'm a bit bummed it doesn't.
|
7

Not possible in plain C. In plain C all file access happens via FILE * handles and these can only be created with fopen() and freopen() and in both cases must refer to a file path. As C tries to be as portable as possible, it limits I/O to the absolute bare minimum that probably all systems can support in some way.

If you have POSIX API available (e.g. Linux, macOS, iOS, FreeBSD, most other UNIX systems), you can use fmemopen():

char dataInMemory[] = "This is some data in memory"; FILE * fileDescriptor = fmemopen(dataInMemory, sizeof(dataInMemory), "r"); 

This is a true file handle that can be used with all C file API. It should also allow seeking, something not possible if you work with pipes as pipes support no seeking (you can emulate forward seeking but there is no way to ever seek backwards).

Comments

-1

You can't. Unlike C++, the C model of file I/O isn't open to extension.

2 Comments

fmemopen can return FILE* from buffer, but fileno(fmemopen(...)) return -1. I got another idea: create pipe and feed buffer content to file_pipes[1] by write() function, and we can look the file_pipes[0] as the file descriptor of that buffer. But when I practise this, the write() function just blocked. Is the kernel buffer of pipe not big enough? Thanks
That's POSIX, IIRC. Not C, which is how you tagged your question. I.e. it wouldn't work on Windows.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.