珍惜危险远离生命 發表於 2023-7-16 00:00:00

Linux中文件描述符fd与文件指针FILE*互相转换实例解析

<p>
        本文研究的主要是linux中文件描述符fd与文件指针file*互相转换的相关内容,具体介绍如下。</p>
<p>
        <strong>1.文件描述符fd的定义:</strong>文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于unix、linux这样的操作系统。</p>
<p>
        <strong>2.文件指针file定义说明文件指针的一般形式为:</strong></p>
<p>
        file *指针变量标识符;</p>
<p>
        其中file应为大写,它实际上是由系统定义的一个结构,该结构中含有文件名、文件状态和文件当前位置等信息。在编写源程序时不必关心file结构的细节。</p>
<p>
        使用系统调用的时候用文件描述符的时候比较多,但是操作比较原始。c库函数在i/o上提供了一些方便的包装(比如格式化i/o、重定向),但是对细节的控制不够。</p>
<p>
        如果过度依赖其中的一种只会徒增麻烦,所以知道两者的转换是很有必要的。file*是对fd的封装</p>
<p>
        当然,有人会说知道文件路径的话重新打开就是了,但是这会产生竞争条件(race conditions),首先重新打开文件,相当于是2个fd指向同一文件,然后如果在打开的期间文件被删除了又被新建了一个同名文件,2个fd指向的便是不同的文件。</p>
<p>
        glibc库提供了两个转换函数fdopen(3)和fileno(3),都是&lt;stdio.h&gt;中的</p>
<p>
        <code>file *fdopen(int fd, const char *mode);<br>
        int fileno(file *stream);</code></p>
<p>
        ps:为了节省篇幅,还是继续忽略返回值的检查。</p>
<p>
        来看看测试吧,是不是我们想的那样。</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_738125">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                        <div class="line number4 index3 alt1">
                                                                4</div>
                                                        <div class="line number5 index4 alt2">
                                                                5</div>
                                                        <div class="line number6 index5 alt1">
                                                                6</div>
                                                        <div class="line number7 index6 alt2">
                                                                7</div>
                                                        <div class="line number8 index7 alt1">
                                                                8</div>
                                                        <div class="line number9 index8 alt2">
                                                                9</div>
                                                        <div class="line number10 index9 alt1">
                                                                10</div>
                                                        <div class="line number11 index10 alt2">
                                                                11</div>
                                                        <div class="line number12 index11 alt1">
                                                                12</div>
                                                        <div class="line number13 index12 alt2">
                                                                13</div>
                                                        <div class="line number14 index13 alt1">
                                                                14</div>
                                                        <div class="line number15 index14 alt2">
                                                                15</div>
                                                        <div class="line number16 index15 alt1">
                                                                16</div>
                                                        <div class="line number17 index16 alt2">
                                                                17</div>
                                                        <div class="line number18 index17 alt1">
                                                                18</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;stdio.h&gt;</code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;unistd.h&gt;</code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;fcntl.h&gt;</code>
</div>
                                                                <div class="line number4 index3 alt1">
                                                                         </div>
                                                                <div class="line number5 index4 alt2">
                                                                        <code class="cpp color1 bold">int</code> <code class="cpp plain">main()</code>
</div>
                                                                <div class="line number6 index5 alt1">
                                                                        <code class="cpp plain">{</code>
</div>
                                                                <div class="line number7 index6 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* filename = </code><code class="cpp string">"new.txt"</code><code class="cpp plain">;</code>
</div>
                                                                <div class="line number8 index7 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp color1 bold">int</code> <code class="cpp plain">fd = open(filename, o_rdwr | o_creat, s_irusr | s_iwusr);</code>
</div>
                                                                <div class="line number9 index8 alt2">
                                                                         </div>
                                                                <div class="line number10 index9 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">file* fp = fdopen(fd, </code><code class="cpp string">"w+"</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number11 index10 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp color1 bold">int</code> <code class="cpp plain">fd2 = fileno(fp);</code>
</div>
                                                                <div class="line number12 index11 alt1">
                                                                         </div>
                                                                <div class="line number13 index12 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"fd=%d | fd2=%d\n"</code><code class="cpp plain">, fd, fd2);</code>
</div>
                                                                <div class="line number14 index13 alt1">
                                                                         </div>
                                                                <div class="line number15 index14 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp functions bold">fclose</code><code class="cpp plain">(fp);</code>
</div>
                                                                <div class="line number16 index15 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">close(fd);</code>
</div>
                                                                <div class="line number17 index16 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">return</code> <code class="cpp plain">0;</code>
</div>
                                                                <div class="line number18 index17 alt1">
                                                                        <code class="cpp plain">}</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_25177">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp plain">$ gcc test.c </code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp plain">$ ./a.out </code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp plain">fd=3 | fd2=3</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        参考fileno手册:</p>
<blockquote>
        <p>
                the function fileno() examines the argument stream and returns its integer descriptor.</p>
</blockquote>
<p>
        file是对fd的封装,fileno()是直接取得被封装的fd,因此并未创建新的fd指向该文件。</p>
<p>
        <strong>参考fdopen手册:</strong></p>
<blockquote>
        <p>
                the fdopen() function associates a stream with the existing file descriptor, fd. the mode of<br>
                the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the<br>
                mode of the file descriptor.</p>
</blockquote>
<p>
        fdopen()是讲流(file对象)与已存在的文件描述符fd进行关联,因此也是未创建新的fd。值得注意的是,file指针的模式(mode)必须与文件描述符的模式兼容。</p>
<p>
        关于mode参数先搁置会儿,目前我们知道的是,使用fileno和fdopen进行转换,都是在原有的fd上进行操作,并未产生新的fd。那么,再次审视刚才的代码,是否发现了问题?</p>
<p>
        我们来检查下close(fd)的返回值,把close(fd)改成下列代码</p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_917596">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                        <div class="line number4 index3 alt1">
                                                                4</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp keyword bold">if</code> <code class="cpp plain">(-1 == close(fd)) {</code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp functions bold">perror</code><code class="cpp plain">(</code><code class="cpp string">"close"</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp functions bold">exit</code><code class="cpp plain">(1);</code>
</div>
                                                                <div class="line number4 index3 alt1">
                                                                        <code class="cpp plain">}</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_548762">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp plain">$ gcc test.c </code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp plain">$ ./a.out </code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp plain">close: bad file descriptor</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        没错,fclose在关闭文件指针的时候,内部其实也关闭了文件描述符(否则资源就泄露了),既然这里fp内部的文件描述符和fd是同一个,当fp被关闭时,fd也被关闭了,再次关闭fd就会出现“损坏的文件描述符”错误。</p>
<p>
        ok,现在回顾下fopen的第2个参数,又r/r+/w/w+/a/a+一共6种设置(windows平台的rb/rb+/wb/wb+暂且不谈),对比linux手册我将对应的open设置列出来</p>
<p>
        <img title="Linux中文件描述符fd与文件指针FILE*互相转换实例解析" alt="Linux中文件描述符fd与文件指针FILE*互相转换实例解析" id="theimg" src="https://zhuji.jb51.net/uploads/img/202305/0bd9c7c431f1730307429fd363322f65.jpg"></p>
<p>
        <strong>依然是进行测试,修改fd_mode和fp_mode,看看实验结果</strong></p>
<div class="jb51code">
        <div>
                <div class="syntaxhighlightercpp" id="highlighter_481324">
                        <div class="toolbar">
                                <span>?</span>
</div>
                        <table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
                                                        <div class="line number1 index0 alt2">
                                                                1</div>
                                                        <div class="line number2 index1 alt1">
                                                                2</div>
                                                        <div class="line number3 index2 alt2">
                                                                3</div>
                                                        <div class="line number4 index3 alt1">
                                                                4</div>
                                                        <div class="line number5 index4 alt2">
                                                                5</div>
                                                        <div class="line number6 index5 alt1">
                                                                6</div>
                                                        <div class="line number7 index6 alt2">
                                                                7</div>
                                                        <div class="line number8 index7 alt1">
                                                                8</div>
                                                        <div class="line number9 index8 alt2">
                                                                9</div>
                                                        <div class="line number10 index9 alt1">
                                                                10</div>
                                                        <div class="line number11 index10 alt2">
                                                                11</div>
                                                        <div class="line number12 index11 alt1">
                                                                12</div>
                                                        <div class="line number13 index12 alt2">
                                                                13</div>
                                                        <div class="line number14 index13 alt1">
                                                                14</div>
                                                        <div class="line number15 index14 alt2">
                                                                15</div>
                                                        <div class="line number16 index15 alt1">
                                                                16</div>
                                                        <div class="line number17 index16 alt2">
                                                                17</div>
                                                        <div class="line number18 index17 alt1">
                                                                18</div>
                                                        <div class="line number19 index18 alt2">
                                                                19</div>
                                                        <div class="line number20 index19 alt1">
                                                                20</div>
                                                        <div class="line number21 index20 alt2">
                                                                21</div>
                                                </td>
                                                <td class="code">
                                                        <div class="container">
                                                                <div class="line number1 index0 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;stdio.h&gt;</code>
</div>
                                                                <div class="line number2 index1 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;stdlib.h&gt;</code>
</div>
                                                                <div class="line number3 index2 alt2">
                                                                        <code class="cpp preprocessor">#include &lt;unistd.h&gt;</code>
</div>
                                                                <div class="line number4 index3 alt1">
                                                                        <code class="cpp preprocessor">#include &lt;fcntl.h&gt;</code>
</div>
                                                                <div class="line number5 index4 alt2">
                                                                         </div>
                                                                <div class="line number6 index5 alt1">
                                                                        <code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">security = s_irusr | s_iwusr;</code>
</div>
                                                                <div class="line number7 index6 alt2">
                                                                        <code class="cpp keyword bold">const</code> <code class="cpp color1 bold">int</code> <code class="cpp plain">fd_mode = o_rdwr | o_creat | o_trunc;</code>
</div>
                                                                <div class="line number8 index7 alt1">
                                                                        <code class="cpp keyword bold">const</code> <code class="cpp color1 bold">char</code><code class="cpp plain">* fp_mode = </code><code class="cpp string">"r"</code><code class="cpp plain">;</code>
</div>
                                                                <div class="line number9 index8 alt2">
                                                                         </div>
                                                                <div class="line number10 index9 alt1">
                                                                        <code class="cpp color1 bold">int</code> <code class="cpp plain">main()</code>
</div>
                                                                <div class="line number11 index10 alt2">
                                                                        <code class="cpp plain">{</code>
</div>
                                                                <div class="line number12 index11 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp color1 bold">int</code> <code class="cpp plain">fd = open(</code><code class="cpp string">"new.txt"</code><code class="cpp plain">, fd_mode, security);</code>
</div>
                                                                <div class="line number13 index12 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">file* fp = fdopen(fd, fp_mode);</code>
</div>
                                                                <div class="line number14 index13 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">if</code> <code class="cpp plain">(fp == null) {</code>
</div>
                                                                <div class="line number15 index14 alt2">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">perror</code><code class="cpp plain">(</code><code class="cpp string">"fdopen"</code><code class="cpp plain">);</code>
</div>
                                                                <div class="line number16 index15 alt1">
                                                                        <code class="cpp spaces">    </code><code class="cpp functions bold">exit</code><code class="cpp plain">(1);</code>
</div>
                                                                <div class="line number17 index16 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">}</code>
</div>
                                                                <div class="line number18 index17 alt1">
                                                                         </div>
                                                                <div class="line number19 index18 alt2">
                                                                        <code class="cpp spaces">  </code><code class="cpp plain">close(fd);</code>
</div>
                                                                <div class="line number20 index19 alt1">
                                                                        <code class="cpp spaces">  </code><code class="cpp keyword bold">return</code> <code class="cpp plain">0;</code>
</div>
                                                                <div class="line number21 index20 alt2">
                                                                        <code class="cpp plain">}</code>
</div>
                                                        </div>
                                                </td>
                                        </tr></tbody></table>
</div>
        </div>
</div>
<p>
        在fd_mode等价于"w+"时,fp_mode的6种设置(r/r+/w/w+/a/a+)均返回非空指针。</p>
<p>
        在fd_mode等价于"w"时,fp_mode6种设置只有"a"和"w"返回非空指针。</p>
<p>
        继续尝试"r"/"r+"/"a"/"a+"的设置,可以发现所谓“兼容”只与读写权限有关,o_rdwr兼容o_rdonly和o_wronly,而后两者则只与自身兼容。</p>
<p>
        有意思的是o_append(在末尾添加)和o_trunc(截断文件从头添加)也兼容。</p>
<blockquote>
        <p>
                the file position indicator of the new stream is set to that<br>
                belonging to fd, and the error and end-of-file indicators are cleared. modes "w" or "w+" do<br>
                not cause truncation of the file. the file descriptor is not dup'ed, and will be closed when<br>
                the stream created by fdopen() is closed.</p>
</blockquote>
<p>
        继续查看fdopen的手册内容,可以看到"w"和"w+"在这里不会导致文件截断。</p>
<p>
        后一句也印证了我们前面的实验结果:文件描述符不会被复制,文件指针被关闭时文件描述符也会被关闭。</p>
<p>
        ps:其实fdopen的手册上还有最后一句:the result of applying fdopen() to a shared memory object is undefined.</p>
<p>
        将fdopen用于共享内存对象的结果是未定义的。</p>
<p>
        <span><strong>总结</strong></span></p>
<p>
        以上就是本文关于linux中文件描述符fd与文件指针file*互相转换实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!</p>
<p>
        原文链接:http://www.cnblogs.com/Harley-Quinn/p/7481593.html</p>
頁: [1]
查看完整版本: Linux中文件描述符fd与文件指针FILE*互相转换实例解析