目录:1、文件I/O1.1----C标准函数与系统函数的区别1.2----PCB概念1.3----open/close1.4----read/write1.5----阻塞和非阻塞1.6----lseek1.7----fcntl1.8----ioctl1.1C标准函数与系统函数的区别
有一定编程基础的男子伴应当都接触过文件编程吧,file.
在C语言上面是包一个的头
每一个文件都有一个缓冲区,C和系统函数的区别也不想说太多,系统函数可以实现不同进程共享一个缓冲区,而C函数不行。
1.2PCB的概念
PCB(processcontrolblock),进程控制块。
Linux的进程控制块为一个由结构task_struct所定义的数据结构,task_struct存/include/linux/sched.h中,其中包括管理进程所需的各类信息。
在创建一个新进程时,系统在显存中申请一个空的task_struct区,即空闲PCB块,并填入所需信息。
1.3open/close
首先了解一下文件描述符,和文件描述符表。
注意:以下内容记住基于进程,所以文件描述符和符表都存在PCB上面了。
文件描述符表:纪录文件描述符使用情况的表。
文件标书符:在一个进程创建时吗,默认手动打开三个文件,即生成了三个文件描述符:
STDINFILENO—>0
STDOUT_FILENO—>1
STDERR_FILENO—>2
标准输入输出流和标准错误流
然后再开辟新文件都会生成新的文件描述符,默认使用空闲的最小的文件描述符。
这儿就可以将输入输出重定向:关掉输入输出流,而后重新打开文件,就可以将输入输出重定向到新开文件中。
好,我们来看如何打开文件z
#include
#include
#include
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
//一般用fd接收返回值
//返回值 :成功返回重新分配的文件描述符,出错则返回-1并设置errno
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
参数释义:
pathname:要打开或创建的文件名,既可以是绝对目录,也可以是相对目录。
flags:打开模式:
O_RDONLY以只读方式打开
O_WRONLY以只写方式打开
O_RDWR可读可写方式打开
O_APPEND表示追加,从文件末尾添加内容,而不覆盖原有内容
O_CREAT若文件不存在则创建,仅此处会用到第三个参数,赋于文件权限
O_EXCL和O_CREAT共用,假如文件已存在则出错返回
O_TRUNC这个咱也没用过,假如文件已存在,但是有可写模式打开linux 文件锁linux 文件锁linux设置默认网关,则将其厚度截断为0字节
O_NONBLOCK对于设备文件,做非阻塞I/O.
第三个参数指定权限,以八补码数表示。
再看一下怎样关掉文件
#include
int close(int fd);
//返回值:成功返回0,失败返回-1并设置errno
- 1
- 2
- 3
- 4
- 5
参数释义:
fd为要关掉的文件描述符。
在进程结束时,系统手动调用close关掉所有文件。
1.4read/write
read函数从打开的文件中读取数据
write函数向打开的文件中写入数据
#include
ssize_t read(int fd,void *buf,size_t count);
ssize_t write(int fd,void *buf,size_t count);
//返回值:成功返回读取/写入的字节数,失败返回-1并设置errno。
- 1
- 2
- 3
- 4
- 5
- 6
参数释义:
fd:文件描述符
buf:缓存,通常用char链表
count:要读取/写入的字节数
ssize_t:表示有符号的size_t。
有些情况下,count可能不会这么正好。
从终端设读,一般以行为单位,读到换行符就返回了
从网路读前面socket部份会再说
1.5阻塞和非阻塞
读常规文件是不会阻塞的
从终端设备或网路读取就不一定了
假如终端输入的数据没有换行符,调用read的终端设备都会阻塞
假如网路上没有收到数据包,调用read从网路读都会阻塞
至于阻塞多久那就不确定了
假如仍然没有数据到就始终阻塞在哪里
解决阻塞的一个办法叫协程
1.6lseek
每位打开的文件就会纪录当前读写的位置,不过那种O_APPEND比较特殊点。
也可以通过lseek来人为操控文件表针偏斜位置。
上代码:
#include
#include
off_t lseek(int fd,off_t offset,int whence);
//这里允许偏移超过文件末尾,中间空出来的位置都是0.
- 1
- 2
- 3
- 4
- 5
- 6
参数释义:fd文件描述符
offset:偏斜量
whence:偏斜的起始位置
whence:
SEEK_SET:从文件开始处估算
SEEK_CUR:从当前文件偏斜处估算
SEEK_END:从文件结束处估算
若lseek成功执行,返回一个新的偏斜量。
注意:偏斜以后写入一个空值,不然会偏斜不成功。
1.7fcntl
可以用fcntl对一个已打开的文件进行更改属性,而毋须重新open一个文件
不过这个我是没试过了
不过文件锁须要用到这个
Linux中文件记录锁可以对文件某一区域进行文件记录锁的控制。它是通过fcntl函数来实现的。
#include
#include
int fcntl (int fd,int cmd,struct flck *lock);
//功能说明:管理文件记录锁的操作
//返回值:调用成功返回0,失败返回-1
- 1
- 2
- 3
- 4
- 5
- 6
参数释义:
fd:文件描述符;
cmd:功能符号;
(F_SETLK拿来设置或释放锁;
F_GETLK拿来获得锁信息;)
lock:储存锁信息的结构体表针;
structflock
shortl_type;/*锁的类型/
shortl_whence;/偏斜量的起始位置:/
off_tl_start;/从l_whence的偏斜量/
off_tl_len;/从l_start开始的字节数/
pid_tl_pid;/锁所属进程ID(通常不用)*/
l_type有F_RDLCK读锁、F_WRLCK写锁及F_UNLCK空锁。
l_whence有SEEK_SET、SEEK_CUR和SEEK_END。
l_len为0时表示从起点开始直到最大可能位置为止。
由于这个我也不太会,并且我想会虚拟主机 linux,那就上代码
#include
#include
#include
#include
#include
int main(){
int fd;
struct flock lock; //声明锁变量 if((fd = open("example",O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1)
{
printf("open file errorn");
return -1;
} memset(&lock,0,sizeof(struct flock));//清空锁变量
//设置锁变量
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; //拿到锁则对文件执行后续操作
if(fcntl(fd,F_GETLK,&lock) == 0)
{
//判断该锁是否空锁
if(lock.l_type != F_UNLCK)
{ printf("lock can not by set in fdn");
}
else
{ lock.l_type = F_WRLCK;//要上锁时才给出锁的类型 if(fcntl(fd,F_SETLK,&lock) == 0) printf("set write lock success!n"); else printf("set write lock fail!n"); getchar(); lock.l_type = F_UNLCK;//在释放锁之前将锁置空 fcntl(fd,F_SETLK,&lock);//释放锁
}
}
close(fd);//关闭文件描述符
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
1.8ioctl
ioctl用于向设备发送控制和配置命令,有些命令也须要读写一些数据,并且这种数据是不能用write/read来进行读写的,如并口线啊之类的。
#include
int ioctl(int d,int request,······);
//d是某个设备的文件描述符,request 是ioctl的命令。可变参数取决于request。
//成功返回一个值,也是取决于request,失败返回-1并设置而errno。
- 1
- 2
- 3
- 4
- 5
- 6