文件I/O
目录:
1、文件I/O
1.1 ---- C标准函数与系统函数的区别
1.2 ---- PCB概念
1.3 ---- open/close
1.4 ---- read/write
1.5 ---- 阻塞和非阻塞
1.6 ---- lseek
1.7 ---- fcntl
1.8 ----ioctl
1.1 C标准函数与系统函数的区别
有一定编程基础的小伙伴应该都接触过文件编程吧,file.
 在C语言里面是包一个<file.h>的头
每一个文件都有一个缓冲区,C和系统函数的区别也不想说太多,系统函数可以实现不同进程共享一个缓冲区,而C函数不行。
1.2 PCB的概念
PCB(process control block),进程控制块。
 Linux的进程控制块为一个由结构task_struct所定义的数据结构,task_struct存/include/ linux/sched.h 中,其中包括管理进程所需的各种信息。
 在创建一个新进程时,系统在内存中申请一个空的task_struct区,即空闲PCB块,并填入所需信息。
1.3 open/close
首先了解一下文件描述符,和文件描述符表。
 注意:以下内容记住基于进程,所以文件描述符和符表都存在PCB里面了。
 文件描述符表:纪录文件描述符使用情况的表。
 文件标书符:在一个进程创建时吗,默认自动打开三个文件,即生成了三个文件描述符:
 STDINFILENO —>0
 STDOUT_FILENO —>1
 STDERR_FILENO —>2
 标准输入输出流和标准错误流
之后再开辟新文件就会生成新的文件描述符,默认使用空闲的最小的文件描述符。
 这里就可以将输入输出重定向:关闭输入输出流,而后重新打开文件,就可以将输入输出重定向到新开文件中。
好,我们来看怎么打开文件z
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
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 这个咱也没用过,如果文件已存在,并且有可写模式打开,则将其长度截断为0字节
 O_NONBLOCK 对于设备文件,做非阻塞I/O.
第三个参数指定权限,以八进制数表示。
再看一下如何关闭文件
#include <unistd.h>
int close(int fd);
//返回值:成功返回0,失败返回-1并设置errno
  
 - 1
 - 2
 - 3
 - 4
 - 5
 
参数释义:
 fd为要关闭的文件描述符。
 在进程结束时,系统自动调用close关闭所有文件。
1.4 read/write
read函数从打开的文件中读取数据
 write函数向打开的文件中写入数据
#include <unistd.h>
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.6 lseek
每个打开的文件都会纪录当前读写的位置,不过那个O_APPEND比较特殊点。
 也可以通过lseek来人为操控文件指针偏移位置。
上代码:
#include <sys/types.h>
#include <unistd.h>
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.7 fcntl
可以用fcntl对一个已打开的文件进行修改属性,而不必重新open一个文件
 不过这个我是没试过了
不过文件锁需要用到这个
Linux中文件记录锁可以对文件某一区域进行文件记录锁的控制。它是通过fcntl函数来实现的。
#include <unistd.h>
#include <fcntl.h>
int fcntl (int fd,int cmd,struct flck *lock);
//功能说明:管理文件记录锁的操作
//返回值:调用成功返回0,失败返回-1
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 
参数释义:
 fd:文件描述符;
 cmd:功能符号;
 (F_SETLK用来设置或释放锁;
 F_GETLK用来获得锁信息;)
 lock:存储锁信息的结构体指针;
struct flock
 {
 short l_type; /* 锁的类型 /
 short l_whence; / 偏移量的起始位置: /
 off_t l_start; / 从l_whence的偏移量 /
 off_t l_len; / 从l_start开始的字节数 /
 pid_t l_pid; / 锁所属进程ID(一般不用) */
 }
 l_type有F_RDLCK读锁、F_WRLCK写锁及F_UNLCK空锁。
 l_whence有SEEK_SET、SEEK_CUR和SEEK_END。
 l_len为0时表示从起点开始直至最大可能位置为止。
因为这个我也不太会,但是我想会,那就上代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){
	int fd;
	struct flock lock; //声明锁变量 if((fd = open("example",O_CREAT | O_TRUNC | O_RDWR, S_IRWXU)) == -1)
	{
		printf("open file error\n");
		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 fd\n");
		}
		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.8 ioctl
ioctl用于向设备发送控制和配置命令,有些命令也需要读写一些数据,但是这些数据是不能用write/read来进行读写的,如串口线啊之类的。
#include <sys/ioctl.h>
int ioctl(int d,int request,······);
//d是某个设备的文件描述符,request 是ioctl的命令。可变参数取决于request。
//成功返回一个值,也是取决于request,失败返回-1并设置而errno。
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/103934332
- 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)