Obtaining a file descriptor

Josuttis has given an example of creating a user-defined stream buffer that can be initialized with a file descriptor, so as to write to an arbitrary destination, which may be a file, socket, etc. ("The C++ Standard Library", 2nd Edition, pg 835)

This buffer can be used to initialize an output stream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class fdoutbuf : public std::streambuf
{
  protected:
    int fd;    		// file descriptor

  public:
    fdoutbuf(int _fd) : 
      fd(_fd)
      {
      }

  /// ...
}


class fdostream : public std::ostream
{
  protected:
    fdoutbuf buf;

  /// ...
}



Josuttis then states (pg 837):

If some other file descriptor is available - for example, for a file or a socket - it also can be used as the constructor argument.


The question is how to obtain a file's descriptor?

I have searched the online docs, but there is nothing available that suggests a solution.

Logically, it is possible to obtain a file descriptor only when it either created or subsequently. But how?

Note that a file descriptor is different from a FILE*.

Thanks.
You need to add a public access to dfoutbuf, say getFD(). Then you can write code like:
1
2
if (fdoutbuf* buf = dynamic_cast<fdoutbuf*>stream.rdbuf())
    fd = buf->getFD();
The question is how to obtain a file's descriptor?

On Linux you can get a file descriptor with open: https://linux.die.net/man/3/open
Not sure if there's a way on Windows.
Windows: almost identical to POSIX
(with most POSIX functions and constants having an extra leading underscore in their names)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int main()
{
    const int fd = _open( __FILE__, _O_RDONLY ) ;
    
    if( fd != -1 )
    {
    
        char buffer[100] {} ; 
        int nbytes_read {} ;

        while( ( nbytes_read = _read( fd, buffer, sizeof(buffer) ) ) > 0 )
              _write( 1, buffer, nbytes_read ) ;
          
        _close(fd) ;
    }
    
    else perror(nullptr) ;
}

http://rextester.com/WEGXX53767
I have tried something, based on Thomas's suggestion and it works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
#include <fcntl.h>          /// POSIX file control
#include <unistd.h>

#include "outbuf2.hpp"

using namespace std;


/// Test O/P to file.
void testfile()
{
    const char* filename = "F:/Temp/file.txt";

    int fd = open(filename, O_WRONLY | O_TRUNC);

    if (fd == -1)
    {
       cout << "can't open file";
       return;
    }

    /// stream with buffer writing to file descriptor fd
    fdostream out {fd};

    out << "Hello!" << endl;
}


/// Test O/P to screen.
void testscreen()
{
    /// stream with buffer writing to file descriptor 1
    fdostream out {1};

    out << "Hello, world!" << std::endl;
}


int main()
{
    testfile();
    testscreen();
}



The concept of the user-defined stream buffer works perfectly.

The only problem is that the open() function with the above flags, works only to write to an existing file.

 
    int fd = open(filename, O_WRONLY | O_TRUNC);



If the file to be written to doesn't exist, I have tried the following flag, but it doesn't write anything:

 
    int fd = open(filename, O_CREAT);


I seek guidance on the combination of flags that works to write O/P to a file, whether it exists or not.

Thanks.
The flags specified are formed by or'ing the following values
https://www.freebsd.org/cgi/man.cgi?query=open&sektion=2&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html

For example: O_CREAT /* create file if it does not exist */ | O_WRONLY /* open for writing only */
No, I had tried this combination earlier; on g++, open() returns -1 (error) if the file exists, with this combo.

The following combo doesn't return -1, but the write operation has no effect if the file exists:

 
O_CREAT | O_APPEND


These errors may be specific to g++; I haven't tried it elsewhere.
Of course, there are many workarounds.

For instance, we could first create the O/P file (if it doesn't exist) using C++ fstream, and then write to it using POSIX:

1
2
3
4
5
6
7
/// Open file using C++ std lib if it doesn't exist
ofstream f {"f:/temp/file.txt"};

f.close();


/// POSIX code to open file and write to it ... 
Topic archived. No new replies allowed.