5. 其它I/O系统调用

(1)dup和dup2函数

头文件

#include<unistd.h>

函数

int dup(int oldfd);

int dup2(int oldfd, int newfd);

返回值

若成功返回新文件描述符,出错返回-1

功能

文件描述符的复制(将oldfd复制给newfd

参数

old:原先的文件描述符

newfd: 新文件描述符

备注

(1)由dup返回的新文件描述符一定是当前可用文件描述符中最小数值

(2)用dup2则可以用newfd参数指定新描述符的数值。如果newfd己经打开,则先将其关闭。如果old等于newfd,则dup2返回newfd,而不关闭它。

(3)在进程间通信时可用来改变进程的标准输入和标准输出设备。(4)注意,复制的只是3个内核结构中的文件描述符中的文件表项指针也就是newfd与oldfd指向了同一个文件表项。但要注意并不复制文件表项本身和inode节点项这两个内核数据结构。

【编程实验】1. 自定义的cat命令

//io.h

#ifndef __IO_H__
#define __IO_H__ extern void copy(int fdin, int fdout);//文件复制
extern void set_fl(int fd, int flag); //设置文件状态标志
extern void clr_fl(int fd, int flag); //取消文件状态标志 #endif

//io.c

#include "io.h"
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> //编译命令:gcc -o obj/io.o -Iinclude -c src/io.c #define BUFFER_LEN 1024 //与分区文件块大小一致。可以通过
//tune2fs -l /dev/sda1命令查看 void copy(int fdin, int fdout)
{
char buffer[BUFFER_LEN]; ssize_t size; //保证从文件开始处复制
lseek(fdin, 0L, SEEK_SET);
lseek(fdout, 0L, SEEK_SET); while((size = read(fdin, buffer, BUFFER_LEN)) > ){
if(write(fdout, buffer, size) != size)
{
fprintf(stderr, "write error: %s \n", strerror(errno));
exit();
}
} if (size < )
{
fprintf(stderr, "read error: %s\n",strerror(errno));
exit(); //return 1;
}
} void set_fl(int fd, int flag) //设置文件状态标志
{
//获取原来的文件状态标志
int val = fcntl(fd, F_GETFL); //增加新的文件状态标志
val |= flag; //重新设置文件状态标志
if(fcntl(fd, F_SETFL, val) < )
{
perror("fcntl error");
}
} void clr_fl(int fd, int flag) //取消文件状态标志
{ //获取原来的文件状态标志
int val = fcntl(fd, F_GETFL, val); //清除指定的文件状态标志(置0)
val &= ~flag; //重新设置文件状态标志
if(fcntl(fd, F_SETFL, val) < )
{
perror("fcntl error");
}
}

//cat.c

#include "io.h"
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h> //模拟cat命令,设编译后的程序名也叫cat
//实验1:bin/cat file1.txt file2.txt
//实验2:bin/cat < file1.txt
//实验3:bin/cat > file1.txt int main(int argc, char* argv[])
{
int fd_in = STDIN_FILENO; //
int fd_out = STDOUT_FILENO; // int i = ;
for(i=; i<argc; i++){
//1.输入cat file1.txt file2.txt时会将file1和file2
// 分别拷贝到标准输出,即输出到屏幕
fd_in = open(argv[], O_RDONLY);
if(fd_in < )
{
perror("open error");
continue;
} copy(fd_in, fd_out);
close(fd_in);
}
//2.如果cat命令后面不带参数,则直接接受键盘输入。
//3.如果输入cat < file1.txt,由于<表示输入重定向,Linux
//会将file1.txt这个参数作为输入,复制给STDIN_FILENO。而不会将其
//传给argv参数。即这种情况下,argc==1,表示程序本身,argv中不包含file1.txt。
if(argc == ) copy(fd_in, fd_out); return ;
}

【编程实验】2.dup和dup2实现重定向

//io.h和io.c与上例相同

#include "io.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
/*
* bin/mcat + file1.txt (+为输入重定向)
* bin/mcat - file1.txt (-为输出重定向)
*/ int main(int argc, char* argv[])
{
int fd_in;
int fd_out; int i=; for(i=; i<argc; i++){
if(!strcmp("+", argv[i])){
fd_in = open(argv[++i], O_RDONLY);
if(fd_in < ){
perror("open error");
exit();
} //将标准输入重定向到文件(即,将fd_in的文件表项指针复制给STDIN_FILENO
//因此,STDIN_FILENO文件描述符与fd_in就同时指向同一个文件表项,也就
//同时指向了file1.txt这个文件。
if(dup2(fd_in, STDIN_FILENO) != STDIN_FILENO){
perror("dup2 error");
exit();
} close(fd_in);
}else if(!strcmp("-", argv[i])){ fd_out = open(argv[++i], O_WRONLY | O_CREAT | O_TRUNC, );
if(fd_out < ){
perror("open error");
exit();
} //将标准输出重定向到文件(即,将fd_out的文件表项指针复制给STDOUT_FILENO
//因此,STDOUT_FILENO文件描述符与fd_out就同时指向同一个文件表项,也就
//同时指向了file1.txt这个文件。
if(dup2(fd_out, STDOUT_FILENO) != STDOUT_FILENO){
perror("dup2 error");
exit();
} close(fd_out);
}else{
fd_in = open(argv[i], O_RDONLY);
if(fd_in < ){
perror("open error");
exit();
} if(dup2(fd_in, STDIN_FILENO) != STDIN_FILENO)
{
perror("dup2 error");
exit();
} close(fd_in);
} copy(STDIN_FILENO, STDOUT_FILENO);
} //命令后面不带参数的情况
if(argc ==)
copy(STDIN_FILENO, STDOUT_FILENO); return ;
}

(2)fcntl函数

头文件

#include<unistd.h>

#include <fcntl.h>

函数

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);

int fcntl(int fd, int cmd, struct flock);

返回值

若成功则依赖于cmd,出错为-1。

功能

可以改变己经打开文件的性质,常见的功能:

(1)复制一个现存的描述符,新文件描述符作为函数返回值(cmd=F_DUP)

(2)获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD)

(3)获取/设置文件状态标志(cmd=F_GETFL或F_SETFL)

(4)获取/设置文件锁(cmd=F_SETLK、F_GETLK或F_SETKLW),此时第3个参数为struct flock结构体。

参数

cmd的常见取值:

(1)F_DUPFD:复制文件描述符,新的文件描述符作为函数返回值返回。

(2)F_GETFD/F_SETFD:获取/设置文件描述符,通过第3个参数设置。

(3)F_GETFL/F_SETFL:获取/设置文件状态标志,通过第3个参数设置。可以更改的标志有:O_APPEND、O_NONBLOCK、O_SYNC、O_ASYNC但要注意,O_RDONLY、O_WRONLY和O_RDWR不适用。

【编程实验】设置文件状态标志

//io.h和io.c文件与上例相同

//file_append_flag.c

#include "io.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> //exit
#include <string.h> //strlen
#include <fcntl.h> //O_WRONLY int main(int argc, char* argv[]){
if( argc < ){
printf("usage: %s content destfile\n", argv[]);
exit();
} int fd = open(argv[], O_WRONLY); //注意,这里没设置为追加 if(fd < ){
perror("open error");
exit();
} //设置追加文件标志
set_fl(fd, O_APPEND); sleep(); //为了把定位与写入过程隔开,以便演示多进程同时写入同一文件
//时会出现后启动进程格覆盖之前进程写过的内容。 //往文件尾部追加内容
size_t size = strlen(argv[])*sizeof(char);
if(write(fd, argv[], size)!=size){
perror("write error");
exit();
} close(fd); return ;
}

(3)ioctl函数

头文件

#include<unistd.h>

#include <sys/ioctl.h>

函数

int ioctl(int fd, int request,…);

返回值

成功为0,出错为-1

功能

控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段

备注

I/O操作的杂物箱。不能用本章中其他函数表示的I/O操作通常都能用ioctl表示。终端I/O是ioctl的最大使用方面,主要用于设置的I/O控制。

【编程实验】读取键盘内容

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h> //for ioctl
#include <linux/input.h> //keyboard //说明本程序须在虚拟机,而不能在远程终端上运行! int main(int argc, char * argv[])
{
int fd = -;
char name[]="unknow";
struct input_event event; int ret = ; if(( fd = open("/dev/input/event2", O_RDONLY)) < ){
perror("open error");
exit();
} //通用EVIOCGNAME命令获取设备名字
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < ){
perror("evdev ioctl error\n");
exit();
} printf("The device's name is %s\n", name); while()
{
ret = read(fd, &event, sizeof(event));
if(ret < ){
printf("read event error\n");
} if(EV_KEY == event.type) //EV_KEY表示按键类事件,类似的有EV_PWR(电源)、EV_SND(声音)事件
{
//if the event is a key code
printf(" key code is %d \n", event.code); //quit,press 'q' to quit this application.
if(event.code == ){
break;
}
}
} return ;
}

第3章 文件I/O(4)_dup、dup2、fcntl和ioctl函数的更多相关文章

  1. perl5 第五章 文件读写

    第五章 文件读写 by flamephoenix 一.打开.关闭文件二.读文件三.写文件四.判断文件状态五.命令行参数六.打开管道 一.打开.关闭文件   语法为open (filevar, file ...

  2. 零基础学Python--------第10章 文件及目录操作

    第10章 文件及目录操作 10.1 基本文件操作 在Python中,内置了文件(File)对象.在使用文件对象时,首先需要通过内置的open() 方法创建一个文件对象,然后通过对象提供的方法进行一些基 ...

  3. UNIX环境高级编程 第3章 文件I/O

    前面两章说明了UNIX系统体系和标准及其实现,本章具体讨论UNIX系统I/O实现,包括打开文件.读文件.写文件等. UNIX系统中的大多数文件I/O只需要用到5个函数:open.read.write. ...

  4. 第三章 文件 I/O

    3.1 引言 先说明可用的文件 I/O 函数:open.read.write.close,然后说明不同缓冲区长度对read和write函数的影响. 本章所说的函数经常被称为不带缓冲的 I/O (unb ...

  5. apue学习笔记(第三章 文件I/O)

    本章开始讨论UNIX系统,先说明可用的文件I/O函数---打开文件.读写文件等 UNIX系统中的大多数文件I/O只需用到5个函数:open.read.write.lseek以及close open函数 ...

  6. 《Unix环境高级编程》读书笔记 第3章-文件I/O

    1. 引言 Unix系统的大多数文件I/O只需用到5个函数:open.read.write.lseek以及close 本章描述的函数经常被称为不带缓冲的I/O.术语不带缓冲指的是在用户的进程中对其不会 ...

  7. 第四章 文件的基本管理和XFS文件系统备份恢复 随堂笔记

    第四章 文件的基本管理和XFS文件系统备份恢复 本节所讲内容: 4.1 Linux系统目录结构和相对/绝对路径. 4.2 创建/复制/删除文件,rm -rf / 意外事故 4.3 查看文件内容的命令 ...

  8. 20190903 On Java8 第十七章 文件

    第十七章 文件 在Java7中对 文件的操作 引入了巨大的改进.这些新元素被放在 java.nio.file 包下面,过去人们通常把nio中的n理解为new即新的io,现在更应该当成是non-bloc ...

  9. Python核心编程(第九章)--文件和输入输出

    文件内建函数: open()函数提供了初始化输入/输出操作的通用接口 open()基本语法:file_object = open(filename,access_mode='r',buffering= ...

随机推荐

  1. 彩信的在android里是如何存储的 Android MMS模块数据存取

    数据表MMS模块总共包含17张表:addr.android_metadata.attachments.canonical_addresses.drm.part.pdu.pending_msgs.rat ...

  2. 单项目实现vendor分离编译,增加编译效率(vue-cli)

    1.在build文件夹下添加文件:webpack.dll.config.js const path = require('path') const webpack = require('webpack ...

  3. (转)2017年12月宋华教授携IBM中国研究院、猪八戒网、中航信托、33复杂美共同论道智慧供应链金融

    今年10月,国务院发布的<关于积极推进供应链创新与应用的指导意见>,不仅强调了发展服务型制造的重要性,同时也指出要积极稳妥发展供应链金融,推动供应链金融服务实体经济,鼓励商业银行.供应链核 ...

  4. IISExpress 开放局域网访问

    1. 设置 IISExpress 配置文件 applicationhost.config VS2015 :这个配置文件 在工程目录下的 .vs/config 隐藏目录 其他版本 :在用户目录中的 II ...

  5. bisect

    # 二分查找算法 import bisect farm = sorted(['haystack', 'needle', 'cow', 'pig']) # ['cow', 'haystack', 'ne ...

  6. css hover遮罩层

    马上月底了, 这个月忙于工作和生活, 没有很好的写一篇博客, 有点忧伤. 为了弥补, 就写点简单的. 最近项目有个需求, 就是鼠标移入的时候显示一个层, 移除的时候这个层消失. 当然层是可以点击进行额 ...

  7. CTF之LSB信息隐藏术

    LSB也就是最低有效位,原理是图片中的像素一般是由三种颜色构成,即三原色(绿红蓝),由这三种颜色可以组成其它各种颜色. 例如在PNG图片的储存中,每个颜色会有8bit,LSB隐写就是修改了像素中的最低 ...

  8. hdu1233 还是畅通工程 最小生成树

    给出修建边的边权,求连通所有点的最小花费 最小生成树裸题 #include<stdio.h> #include<string.h> #include<algorithm& ...

  9. ZH奶酪:隐马尔可夫模型学习小记——forward算法+viterbi算法+forward-backward算法(Baum-welch算法)

    网上关于HMM的学习资料.博客有很多,基本都是左边摘抄一点,右边摘抄一点,这里一个图,那里一个图,公式中有的变量说不清道不明,学起来很费劲. 经过浏览几篇博文(其实有的地方写的也比较乱),在7张4开的 ...

  10. 00.嵌入式Linux开发环境搭建

     3.虚拟机上网配置 虚拟机如果要从网上获取资源,就要能够访问外网.虚拟机有三种上网方式:桥接上网,NAT上网,单主机模式[没用过].本节从原理和操作2个方面讲了NAT方式和桥接方式这2种不同的虚拟机 ...