《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 ...
随机推荐
- spring-mysqlclient开源了
https://github.com/risedragon/spring-mysqlclient/wiki/spring-mysqlclient-user-guide 开源了一个项目,总结了几年的数据 ...
- 关于IOS中的delegate必须知道的事情
当你开始写iOS程式不久,应该开始面对到很多的delegate, 不管是用别人的library或是自己写library,可能都逃不了delegate. 为了怕有些人不知道什么是delegate,在这边 ...
- Export Farm Solution wsp Files SharePoint 2007 and 2010
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")$farm = [Microsof ...
- MS SQL Server中的CONVERT日期格式化大全
CONVERT 将某种数据类型的表达式显式转换为另一种数据类型.由于某些需求经常用到取日期格式的不同. 现以下可在SQL Server中将日期格式化. SQL Server 支持使用科威特算法的阿拉伯 ...
- windows 2012 服务器打开ping端口,开通远程连接
windows 2012 服务器打开ping端口,开通远程桌面连接 控制面板->系统与安全->高级防火墙->入站规则 找到:windows 远程桌面 (http in ) 右键启用 ...
- php多条件查询
$sql)"; if(!empty($uid)) { $sql .=" and uid= ".$uid; } if(!empty($time1) && e ...
- 【POJ】【1067】取石子游戏
博弈论 这个是博弈游戏中的Wythoff博弈: 以下为我的代码: //POJ 1067 #include<cmath> #include<cstdio> #include< ...
- PHP之Error与Logging函数讲解
PHP Error 和 Logging 简介 error 和 logging 函数允许你对错误进行处理和记录. error 函数允许用户定义错误处理规则,并修改记录错误的方式. logging 函数允 ...
- Guava文档翻译之 Service
概览 Guava的接口代表了一个有运行状态的对象,有启动和停止的方法.比如网络服务器,RPC服务器,以及计时器等,都可以实现Service接口.掌管像这样的服务的状态,需要正确地管理启动和关闭,因此会 ...
- 集合、拆箱、装箱、自定义集合的foreach
集合部分 参考:http://msdn.microsoft.com/zh-cn/library/0ytkdh4s(v=vs.110).aspx 集合类型是诸如哈希表.队列.堆栈.包.字典和列表等数据集 ...