dup、文件锁、库函数、函数调用(day07)

一、lseek(2)重新定位文件的读写位置。
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,  off_t  offset,  int whence);
功能:重新定位文件读写位置距离文件起始的偏移
参数:
fd:指定了具体的文件
offset:偏移
whence:
SEEK_SET:offset就是文件的偏移位置   指向文件的头部
SEEK_CUR:代表当前位置   当前位置+offset
SEEK_END:文件的大小+offset     文件的尾部
返回值:
-1   错误   errno被设置
返回的是位置距离文件起始的字节数。
举例说明  lseek(2)的使用.代码参见  lseek.c

补充:
day07$od -tx1 -tc hello
0000000  68  65  6c  6c  6f  0a
          h   e   l   l   o  

0000006

day07$vi hello
day07$od -tx1 -tc hello
0000000  68  65  6c  6c  6f  0a  77  6f  72  6c  64  0a
          h   e   l   l   o  
   w   o   r   l   d  

0000014

二、使用mmap将文件映射到进程的虚拟地址空间,然后对内存的操
作直接反应到文件中。
将文件hello映射到内存,在内存中对文件的内容进行修改,改变实际文件的内容。
代码参见  mmap_file.c

三、文件的重定向
什么是文件的重定向?
我们讲述的文件是流式文件。操作的都是文件流。文件的重定向就是改变文件的流向。文件操作有两种流,输入流和输出流。
文件重定向分为文件输出重定向和文件输入重定向。
文件输出重定向。
完成文件描述符复制的两个系统调用
dup(2)   dup2(2)
#include <unistd.h>
int dup(int oldfd);
功能:复制文件描述符
参数:
oldfd:源文件描述符
返回值:
-1  错误 errno被设置
返回最小的、没有被使用的文件描述符

int dup2(int oldfd, int newfd);
功能:复制文件描述符
参数:
oldfd:源文件描述符
newfd:目的文件描述符
返回值:
-1  错误 errno被设置
成功返回目的文件描述符

举例说明  使用dup(2)和dup2(2)实现文件的输出重定向。
代码参见   direct.c


四、文件锁的使用
文件锁分为两种    读锁(共享锁)        写锁(互斥锁)
文件对锁的实现分为两类     建议锁     强制锁
如何对文件加锁?
使用系统调用fcntl(2)对文件进行加锁。
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:操作文件描述符
参数:
fd:指定要操控的文件描述符
cmd:指定了操作文件描述符的命令
建议锁使用的命令:
F_GETLK:用来测试是否可以加锁,如果可以加锁,返回F_UNLCK。
不可以加锁,在字段l_pid中保存了一个pid。是hold着这把锁的进程的pid。

F_SETLK:为文件描述符设置锁。如果有互斥锁,其他进程hold着互斥锁,立即返回-1,错误,errno被设置

F_SETLKW:和F_SETLK一样,但是如果想要加的锁和文件已有记录锁冲突,进程阻塞等待其他进程对记录锁的释放。

...:  可变参数,参数的类型和个数取决于cmd。
struct flock *
struct flock {
               ...
        short l_type;   /* Type of lock: F_RDLCK,
                                   F_WRLCK, F_UNLCK */
        short l_whence;  /* How to interpret l_start:
                       SEEK_SET, SEEK_CUR, SEEK_END */
        off_t l_start; /* Starting offset for lock */
        off_t l_len;     /* Number of bytes to lock */
     pid_t l_pid; /* PID of process blocking our lock
                        (F_GETLK only) */
               ...
};

返回值:
0  成功
-1  错误   errno被设置

举例说明文件锁的使用
有两个进程PA和PB,PA进程对文件加读锁,测试PB进程对同一个文件也加读锁,是否成功?
代码参见  PA.c PB.c

测试文件锁是否能添加。代码参见PC.c

五、库函数和系统调用之间的关系
以文件操作为例。
fopen    fclose     fputc   fgetc   库函数
open     close      read    write   系统调用

举例说明   代码参见 file.c

FILE    是结构体类型的别名

flags   fileno   mode  

fopen(3)
首先调用open(2),打开一个文件,将open(2)的返回值记录在FILE结构体中的_fileno成员。分配一块内存,这块空间叫文件内容缓冲区。然FILE中的一些指针成员指向这块内存。最后返回FILE类型的对象。

fputc(3)
调用fputc的时候,向文件内容缓冲区写数据。如果缓冲区没有空间接纳这个字符,调用write(2)将缓冲区的数据写入到文件中,然后再将fputc中的数据写入到缓冲区。如果缓冲有空间接纳数据,直接将数据写入缓冲区即可。

fgetc(3)
调用fgetc的时候,首先从缓冲区读取数据,如果缓冲区有数据,理解返回读取到的字节。如果缓冲区没有数据,调用read(2)从文件中读取数据 到缓冲区,然后fgetc了获取到数据才返回。


fclose(3)
首先刷新缓冲区,将缓冲区内存写入到文件中,然后调用close(2)关闭文件描述符,最后释放缓冲区。

库函数操作文件称为缓冲文件。
系统调用操作文件称为非缓冲文件

库函数可以跨平台    系统调用不能跨平台

总结:
一、lseek的使用
二、使用mmap将文件映射到内存,对内存的操作直接反应到文件中
三、文件输出重定向
四、文件锁的使用
五、库函数和系统调用之间的关系
原文地址:https://www.cnblogs.com/Kernel001/p/7732581.html