- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Linux中文件描述符fd与文件指针FILE*互相转换实例解析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文研究的主要是linux中文件描述符fd与文件指针file*互相转换的相关内容,具体介绍如下.
1.文件描述符fd的定义:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于unix、linux这样的操作系统.
2.文件指针file定义说明文件指针的一般形式为:
file *指针变量标识符; 。
其中file应为大写,它实际上是由系统定义的一个结构,该结构中含有文件名、文件状态和文件当前位置等信息。在编写源程序时不必关心file结构的细节.
使用系统调用的时候用文件描述符的时候比较多,但是操作比较原始。c库函数在i/o上提供了一些方便的包装(比如格式化i/o、重定向),但是对细节的控制不够.
如果过度依赖其中的一种只会徒增麻烦,所以知道两者的转换是很有必要的。file*是对fd的封装 。
当然,有人会说知道文件路径的话重新打开就是了,但是这会产生竞争条件(race conditions),首先重新打开文件,相当于是2个fd指向同一文件,然后如果在打开的期间文件被删除了又被新建了一个同名文件,2个fd指向的便是不同的文件.
glibc库提供了两个转换函数fdopen(3)和fileno(3),都是<stdio.h>中的 。
file *fdopen(int fd, const char *mode); int fileno(file *stream),
ps:为了节省篇幅,还是继续忽略返回值的检查.
来看看测试吧,是不是我们想的那样.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int
main()
{
const
char
* filename =
"new.txt"
;
int
fd = open(filename, o_rdwr | o_creat, s_irusr | s_iwusr);
file* fp = fdopen(fd,
"w+"
);
int
fd2 = fileno(fp);
printf
(
"fd=%d | fd2=%d\n"
, fd, fd2);
fclose
(fp);
close(fd);
return
0;
}
|
1
2
3
|
$ gcc test.c
$ ./a.out
fd=3 | fd2=3
|
参考fileno手册:
the function fileno() examines the argument stream and returns its integer descriptor. 。
file是对fd的封装,fileno()是直接取得被封装的fd,因此并未创建新的fd指向该文件.
参考fdopen手册:
the fdopen() function associates a stream with the existing file descriptor, fd. the mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the mode of the file descriptor. 。
fdopen()是讲流(file对象)与已存在的文件描述符fd进行关联,因此也是未创建新的fd。值得注意的是,file指针的模式(mode)必须与文件描述符的模式兼容.
关于mode参数先搁置会儿,目前我们知道的是,使用fileno和fdopen进行转换,都是在原有的fd上进行操作,并未产生新的fd。那么,再次审视刚才的代码,是否发现了问题?
我们来检查下close(fd)的返回值,把close(fd)改成下列代码 。
1
2
3
4
|
if
(-1 == close(fd)) {
perror
(
"close"
);
exit
(1);
}
|
1
2
3
|
$ gcc test.c
$ ./a.out
close: bad file descriptor
|
没错,fclose在关闭文件指针的时候,内部其实也关闭了文件描述符(否则资源就泄露了),既然这里fp内部的文件描述符和fd是同一个,当fp被关闭时,fd也被关闭了,再次关闭fd就会出现“损坏的文件描述符”错误.
ok,现在回顾下fopen的第2个参数,又r/r+/w/w+/a/a+一共6种设置(windows平台的rb/rb+/wb/wb+暂且不谈),对比linux手册我将对应的open设置列出来 。
依然是进行测试,修改fd_mode和fp_mode,看看实验结果 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
const
int
security = s_irusr | s_iwusr;
const
int
fd_mode = o_rdwr | o_creat | o_trunc;
const
char
* fp_mode =
"r"
;
int
main()
{
int
fd = open(
"new.txt"
, fd_mode, security);
file* fp = fdopen(fd, fp_mode);
if
(fp == null) {
perror
(
"fdopen"
);
exit
(1);
}
close(fd);
return
0;
}
|
在fd_mode等价于"w+"时,fp_mode的6种设置(r/r+/w/w+/a/a+)均返回非空指针.
在fd_mode等价于"w"时,fp_mode6种设置只有"a"和"w"返回非空指针.
继续尝试"r"/"r+"/"a"/"a+"的设置,可以发现所谓“兼容”只与读写权限有关,o_rdwr兼容o_rdonly和o_wronly,而后两者则只与自身兼容.
有意思的是o_append(在末尾添加)和o_trunc(截断文件从头添加)也兼容.
the file position indicator of the new stream is set to that belonging to fd, and the error and end-of-file indicators are cleared. modes "w" or "w+" do not cause truncation of the file. the file descriptor is not dup'ed, and will be closed when the stream created by fdopen() is closed. 。
继续查看fdopen的手册内容,可以看到"w"和"w+"在这里不会导致文件截断.
后一句也印证了我们前面的实验结果:文件描述符不会被复制,文件指针被关闭时文件描述符也会被关闭.
ps:其实fdopen的手册上还有最后一句:the result of applying fdopen() to a shared memory object is undefined. 。
将fdopen用于共享内存对象的结果是未定义的.
总结 。
以上就是本文关于linux中文件描述符fd与文件指针file*互相转换实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持! 。
原文链接:http://www.cnblogs.com/Harley-Quinn/p/7481593.html 。
最后此篇关于Linux中文件描述符fd与文件指针FILE*互相转换实例解析的文章就讲到这里了,如果你想了解更多关于Linux中文件描述符fd与文件指针FILE*互相转换实例解析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想知道是否可以访问放在 tomcat 的 conf 文件夹中的文件。通常我会在这个文件中放置多个 webapp 的配置,在 war 之外。 我想使用类路径独立于文件系统。 我过去使用过 lib 文件
我有一个 PowerShell 脚本,它获取文件列表并移动满足特定条件的文件。为什么即使对象为空,foreach 循环也会运行? 我假设如果 $i 不存在,它就不会运行。但是如果 $filePath
我已将 BasicAccountRule.drl 放置在我的 Web 应用程序中,位置为:C:/workspace/exim_design/src/main/resources/rules/drl/i
我使用 File.open('file.txt').class 和 File.open('file.txt').readlines.class 以及前者进行了检查一个返回 File,后者返回 Arra
我正在尝试使用 FileOutputStream 删除文件,在其中写入内容后。这是我用来编写的代码: private void writeContent(File file, String fileC
我正在尝试使用 flink 和 python 批处理 api 测试 Wordcount 经典示例。我的问题是,将数据源从 env.from_elements() 修改为 env.read_text()
我正在尝试制作一个可以同时处理多个不同文件的程序。我的想法是制作一个包含 20 个 FILE* 的数组,以便在我达到此限制时能够关闭其中一个并打开请求的新文件。 为此,我想到了一个函数,它选择一个选项
我有两个文件A和B文件A: 976464 792992 文件B TimeStamp,Record1,976464,8383,ABCD 我想搜索文件 A 和文件 B 中的每条记录并打印匹配的记录。打印的
我有一些保存在 map 中的属性文件。示例: Map map = new HashMap<>(); map.put("1", "One"); map.put("2", "Two"); map.put(
我正在尝试找出一个脚本文件,该文件接受一个包含文件列表的文件(每一行都是一个文件路径,即 path/to/file)并将它们合并到一个文件中。 例如: list.text -- path/to/fil
为了使用 File.CreateText() 和 File.AppendText() 你必须: 通过调用这些方法之一打开流 写消息 关闭流 处理流 为了使用 File.AppendAllText()
使用rsync时,如何在使用--files-from参数复制时重命名文件?我有大约190,000个文件,在从源复制到目标时,每个文件都需要重命名。我计划将文件列表放在一个文本文件中传递给--files
我在非服务器应用程序中使用 Spring(只需从 Eclipse 中某个类的 main() 编译并运行它)。 我的问题是作为 new FileSystemXmlApplicationContext 的
QNX (Neutrino 6.5.0) 使用 ksh 的开源实现作为其 shell 。许多提供的脚本,包括系统启动脚本,都使用诸如 if ! test /dev/slog -ef /dev/slog
当我尝试打开从我的应用程序下载的 xls 文件时,出现此错误: excel cannot open the file because the file format or file extension
有一些相关的概念,即文件指针、流和文件描述符。 我知道文件指针是指向数据类型 FILE 的指针(在例如 FILE.h 和 struct_FILE.h 中声明)。 我知道文件描述符是 int ,例如成员
好吧,这应该很容易... 我是groovy的新手,我希望实现以下逻辑: def testFiles = findAllTestFiles(); 到目前为止,我想出了下面的代码,该代码可以成功打印所有文
我理解为什么以下内容会截断文件的内容: Get-Content | Out-File 这是因为 Out-File 首先运行,它会在 Get-Content 有机会读取文件之前清空文件。 但是当我尝
您好,我正在尝试将文件位置表示为变量,因为最终脚本将在另一台机器上运行。这是我尝试过的代码,然后是我得到的错误。在我看来,python 是如何添加“\”的,这就是导致问题的原因。如果是这种情况,我如何
我有一个只包含一行的输入文件: $ cat input foo bar 我想在我的脚本中使用这一行,据我所知有 3 种方法: line=$(cat input) line=$( input"...,
我是一名优秀的程序员,十分优秀!