《Linux/Unix系统编程手册》读书笔记2
第5章:
主要介绍了文件I/O更深入的一些内容。
原子操作,将一个系统调用所要完成的所有动作作为一个不可中断的操作,一次性执行;这样可以避免竞争状态(两个或多个共享资源的进程或线程的运行结果是一个无法预期的顺序)。
以独占方式创建一个文件:对文件是否存在的检查和创建文件属于同一个原子操作。防止新建文件的时候因为检查文件是否存在和新建文件之间发生中断(而其他进程也在新建相同文件名的文件),导致两个进程都认为自己是文件的创建者。
向文件尾部追加数据:将文件的偏移量的移动与数据的写操作属于同一个原子操作。防止多个进程同时往同一个文件尾部添加数据导致数据混乱。
fcntl(),对一个打开的文件描述符执行一系列的操作。
#include <fcntl.h> int fcntl(int fd, int cmd, ...);
fd为文件描述符,cmd是决定具体操作,第三个参数(可选)用来设置为不同的类型。
cmd参数(部分),具体查看man手册:
F_DUPFD | 复制文件描述符 |
F_GETFD | 获取文件描述符 |
F_SET_FD | 设置文件描述符 |
F_GETFL | 获取文件访问模式和状态标志 |
F_SETFL | 设置文件访问模式和状态标志 |
文件描述符与打开文件之间的关系:多个文件描述符可以指向同一个打开文件。他们的关系如下
文件描述符表、打开文件表和i-node表。打开文件表的条目成为打开文件句柄(open file handle)。
PS:如果两个不同的文件描述符指向同一个打开文件句柄,这两个文件描述符将共享相同的文件偏移量。(打开文件句柄里包含文件偏移量file offset)。
dup(),复制一个打开的文件描述符oldfd,并返回新的描述符。
dup2(),复制oldfd指定的文件描述符,返回newfd参数指定的描述符。
dup3(),参数与dup2()相同,添加了flags,用于修改系统调用行为。
#include <unistd.h> int dup(int oldfd); int dup2(int oldfd, int newfd); int dup3(int oldfd, int newfd, int flags);
成功调用返回新的文件描述符,失败返回-1。
pread()和pwrite(),在指定参数所指定的位置进行文件I/O操作,但不改变文件的偏移量。
#include <unistd.h> ssize_t pread(int fd, void *buf, size_t count, off_t offset); ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
fd为文件描述符,buf为缓冲区, count为缓冲区字节数, offset为偏移量。
pread()成功调用返回读取的字节数,失败返回-1
pwrite()成功调用返回写入的字节数,失败返回-1
------------------------省略分散输入和集中输出,截断文件,非阻塞I/O和大文件I/O等一些知识点---------------
练习:
5-1,请使用标准文件I/O系统调用(open()和lseek())和off_t数据类型修改程序清单5-3中的程序。将宏_FILE_OFFSET_BITS的值设置为64进行编译,并测试该程序是否能够成功创建一个大文件。
/*
* =====================================================================================
*
* Filename: large_file.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月17日 22时05分50秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #define _FILE_OFFSET_BITS 64
#include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h" int main(int argc, char *argv[]){
int fd;
off_t off;
if(argc != || strcmp(argv[], "--help") == )
usageErr("%s pathname offset\n", argv[]); fd = open(argv[], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if(fd == -)
errExit("open"); off = atoll(argv[]);
if(lseek(fd, off, SEEK_SET) == -)
errExit("lseek"); if(write(fd, "test", ) == -)
errExit("write");
exit(EXIT_SUCCESS); }
测试结果:
lancelot@debian:~/Code/tlpi$ ./large_file largefile
lancelot@debian:~/Code/tlpi$ ls -l largefile
-rw------- lancelot lancelot 4月 : largefile
5-2,编写一个程序,使用O_APPEND标志并以写方式打开一个已存在的文件,且将文件偏移量置于起始位置,再写入数据。数据会显示在文件中的哪个位置?为什么?
/*
* =====================================================================================
*
* Filename: 5-2.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月17日 22时26分51秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>
#include "tlpi_hdr.h" int main(int argc, char *argv[]){
int fd;
off_t off;
ssize_t numWritten; if(argc != || strcmp(argv[], "--help") == )
usageErr("%s file", argv[]); fd = open(argv[], O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
if(fd == -)
errExit("open"); off = lseek(fd, , SEEK_SET);
if(off == -)
errExit("lseek"); numWritten = write(fd, "Kevin Durant\n", );
if(numWritten == -)
errExit("write"); close(fd);
exit(EXIT_SUCCESS);
}
测试结果:
lancelot@debian:~/Code/tlpi$ cat t1
This is the second line.
This is the third line.
This is the append line. lancelot@debian:~/Code/tlpi$ ./write_append t1
lancelot@debian:~/Code/tlpi$ cat t1
This is the second line.
This is the third line.
This is the append line. Kevin Durant
5-3,本习题的设计目标在于展示为何以O_APPEND标志打开文件来保障操作的原子性是必要的。请编写一程序,可接收多达3个命令行参数:
$ automic_append filename num-bytes [x]
该程序应打开制定的文件,然后以每次调用write()写入一个字节的方式,向文件尾部追加num-bytes个字节。缺省情况下,程序使用O_APPEND标志打开文件,但若存在第三个命令行参数(x),那么打开文件时将不再使用O_APPEND标志,代之以调用write()前调用lseek(fd, 0, SEEK_END)。同时运行该程序的两个实例,不带x参数,将100万字节写入同一个文件:
$ automic_append f1 1000000 & automic_append f1 1000000
重复上述操作,将数据写入另一个文件,但运行时加入x参数
$ automic_append f2 1000000 x & automic_append f2 1000000 x
使用ls -l命令检查文件f1和f2的大小, 并解释两文件大小不同的原因。
/*
* =====================================================================================
*
* Filename: atomic_append.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月17日 22时46分49秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h" int main(int argc, char *argv[]){
int i, fd, flags, numBytes;
off_t off;
ssize_t numWritten; flags = O_RDWR | O_CREAT;
if(argc < || strcmp(argv[], "--help") == )
usageErr("%s filename num-bytes [x]"); if(argc != )
flags = flags | O_APPEND; numBytes = getInt(argv[], , "num-bytes"); fd = open(argv[], flags, S_IRUSR | S_IWUSR);
if(fd == -)
errExit("open"); /*if(argc == 4)
if(lseek(fd, 0, SEEK_END) == -1)
errExit("lseek"); */ for(i = ; i < numBytes; ++i){
if(argc > && argv[] == "x")
if(lseek(fd, , SEEK_END) == -)
errExit("lseek"); if(write(fd, "A", ) != )
fatal("write() failed");
} exit(EXIT_SUCCESS);
}
测试结果:
lancelot@debian:~/Code/tlpi$ ls -l f1 f2
-rw------- lancelot lancelot 4月 : f1
-rw------- lancelot lancelot 4月 : f2
5-4,使用fcntl()和close()来实现dup()和dup2()。务必牢记dup2()需要处理的一种特殊情况,即oldfd与newfd相等。这时,应检查oldfd是否有效,测试fcntl(oldfd, F_GETFL)是否成功就能达到这一目标。若oldfd无效,则dup2()将返回-1,并将errno置为EBADF。
/*
* =====================================================================================
*
* Filename: 5-4.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月19日 08时48分46秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #include <sys/stat.h>
#include <fcntl.h>
#include "tlpi_hdr.h" int Dup(int oldfd); int Dup2(int oldfd, int newfd); int main(){
int fd;
int newfd;
if((fd = open("t1", O_RDONLY)) == -)
errExit("open"); //newfd = fcntl(fd, F_DUPFD, fd+1);
newfd = Dup(fd);
if(newfd == -)
errExit("Dup"); printf("old fd is %d, new fd is %d\n", fd, newfd); printf("Input the new fd:");
scanf("%d", &newfd); /*if(fcntl(oldfd, F_GETFL) == -1)
errExit("fd is ")
*/ newfd = Dup2(fd, newfd);
if(newfd == -)
errExit("Dup2");
printf("old fd is %d, new fd is %d\n", fd, newfd); exit(EXIT_SUCCESS);
} int Dup(int oldfd){
int newfd = fcntl(oldfd, F_DUPFD, oldfd+);
return newfd;
} int Dup2(int oldfd, int newfd){
int fd = newfd;
if(fcntl(oldfd, F_GETFL) == -){
errno = EBADF;
return -;
}
if(oldfd == newfd)
return newfd;
else{
if(fcntl(newfd, F_GETFL) != -)
close(newfd);
newfd = fcntl(oldfd, F_DUPFD, fd);
if(newfd != fd)
newfd = fcntl(newfd, F_SETFD, fd); return newfd;
}
}
测试结果:
lancelot@debian:~/Code/tlpi$ ./my_dup
old fd is , new fd is
Input the new fd:
old fd is , new fd is
《Linux/Unix系统编程手册》读书笔记2的更多相关文章
- <数据挖掘导论>读书笔记11异常检测
异常检测的目标是发现与大部分其他对象不同的对象.通常,异常对象被称作离群点(Outlier). 异常检测也称偏差检测(Deviation detection),因为异常对象的属性值明显偏离期望的或者常 ...
- <数据挖掘导论>读书笔记10聚类分析续
基于原型的聚类 模糊c均值使用模糊逻辑和模糊集合论的概念,提出一种聚类方案,它很像K均值,但是不需要硬性地将对象分派到一个簇中.模糊c均值算法有时也称为FCM 混合模型聚类采取这样的访谈,簇集合可以用 ...
- <数据挖掘导论>读书笔记9聚类分析
1. 聚类分析仅根据在数据中发现的描述对象及其关系的信息,将数据对象分组. 其目标是组内的对象相互之间是相似的或者相关的,而不同组中的对象是不同的或者不相关的. 2.聚类分析的重要技术 K均值:K均值 ...
- <数据挖掘导论>读书笔记8FP树
1FP树
- <数据挖掘导论>读书笔记7 Apriori算法
Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法.其核心是基于两阶段频集思想的递推算法.该关联规则在分类上属于单维.单层.布尔关联规则.在这里,所有支持度大于最小支持度的项集称为频繁项 ...
- <数据挖掘导论>读书笔记4--其他分类技术
1.基于规则的分类器 2.最近邻分类器 3.贝叶斯分类器 4.人工神经网络 5.支持向量机 6.组合方法 7.不平衡类问题 8.多类问题
- <数据挖掘导论>读书笔记6关联分析的高级概念
处理联系属性: 基于离散化的方法 基于统计学的方法 非离散化方法 处理概念分层 定义在一个特定领域的各种实体或者概念的多层组织.概念分层可以用有向无环图DAG来标示. 序列模式 可选计数方案 COBJ ...
- <数据挖掘导论>读书笔记5关联分析的基本概念和算法
关联规则的强度可以用support度和confidence(置信)度来度量 关联规则发现 给定事务的集合T,关联规则发现是指找出支持度大于等于minsup并且置信度大于等于minconf的所有规则, ...
- <数据挖掘导论>读书笔记3--分类
1.分类的基本概念 分类任务就是通过学习得到一个目标函数f,把每个属性集x映射到一个预先定义的类标号y 目标函数也称为分类模型. 2. 解决分类问题的一般方法: 决策树分类法 基于规则的分类法 神经网 ...
- <数据挖掘导论>读书笔记2
1.频率和众数 frequency(vi)=具有属性值vi的对象数/m 分类属性的众数mode是具有最高频率的值. 2.百分位数 3.位置度量:均值和中位数 4.散布度量:极差和方差 绝对平均偏差 A ...
随机推荐
- XenServer安装虚拟机---先扩容存放ISO镜像文件
我们都知道xenserver安装后,不管你的盘有多大,只有4G的空间. 故操作是:新建LV卷,可自定义大小 1.vgdisplay #先查看剩余空间 [root@XenServer /]# vgdis ...
- String面试题
//a b c 分别是怎么存储的, a和b a和c分别有什么区别// c和d的区别是什么 String a= "hello";String b= "hello" ...
- visuall assist x 破解方法
visuall assist x 破解方法 试用期过了后,不管怎么装,或者是找网上的KEY都不行,所以试了一下的方法,成功了: 1.先下载Visual Assist X 10.6.1845.0 2 ...
- (Android学习系列)三,窗口的常用事件
设置窗口标题事件和在Activity之间跳转 新建一个项目,新建两个Activity:MainActivity,TitleActivity ,然后再AnroidManifest.xml 中注册Titl ...
- C#调用Python 脚本语言
1. 安装IronPython http://pan.baidu.com/s/1qW4jNJ2 下载IronPython 2.7 安装下载下来的安装包 2. 创建项目 创建一个C#的Windows窗 ...
- Java Day 06
二维数组 定义: 格式1 int[][] arr = new int[3][2]; 格式2 int[][] arr = new int[3][];//每个一维数组初始化时为null 空指针异常 格式3 ...
- getHeight returns 0 for all Android UI objects
It's 0 because in both onCreate and onStart, the view hasn't actually been drawn yet. You can get ar ...
- [algothrim]URL相似度计算的思考
http://www.spongeliu.com/399.html http://in.sdo.com/?p=865
- Linux查看系统基本信息
问题描述: 查看系统基本信息 问题解决: (1)lspci 是一个用来显示系统中所有PCI总线设备或连接到该总线上的所有设备的工具. 用法: lspci -v (1.1) ...
- 【BZOJ】【3669】【NOI2014】魔法森林
LCT动态维护MST LCT动态维护MST 我们可以枚举a,然后找从1到n的一条路径使得:这条路径上的b的最大值最小.这个路径肯定在MST上……所以枚举一遍所有的边,动态维护一个关于b值的MST即可. ...