文件共享

一个进程打开了两个文件

文件表条目(file-table-entry):

1.文件状态标志(file-status-flags): 读/写/追加/同步/非阻塞等;

2.当前文件偏移量

3.v节点指针

//验证
int main(int argc, char *argv[])
{
    int fd1 = open("test.txt", O_RDONLY);
    if (fd1 == -1)
        err_exit("fd1 open O_RDONLY error");
    int fd2 = open("test.txt", O_RDWR);
    if (fd2 == -1)
        err_exit("fd2 open O_RDWR error");

    //读取fd1
    char buf[BUFSIZ];
    if (read(fd1, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "fd1: " << buf << endl;

    //读取fd2
    bzero(buf, 10);
    if (read(fd2, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "fd2: " << buf << endl;

    lseek(fd1, 0, SEEK_SET);
    lseek(fd2, 0, SEEK_SET);
    write(fd2, "Helloworld", 10);
    bzero(buf, 10);
    if (read(fd1, buf, 10) == -1)
        err_exit("read fd1 error");
    cout << "after fd2 write: " << buf << endl;
}

两个独立的进程打开同一个文件

复制文件描述符

方法有三种:

1.dup

2.dup2

#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
//示例
int main(int argc, char *argv[])
{
    int fd = open("text.txt", O_WRONLY|O_TRUNC);
    if (fd == -1)
        err_exit("open O_WRONLY error");

//    close(1);   //将标准输出关闭, 则文件描述符1将空闲
//    int dupfd = dup(fd);
    int dupfd = dup2(fd, 1);
    cout << "dupfd = " << dupfd << endl;
}
/** 示例: 实现文件拷贝
其中execlp会在后面介绍
**/
int main(int argc, char *argv[])
{
    if (argc < 3)
        err_quit("usage: ./main file-name1 file-name2");

    close(STDIN_FILENO);
    open(argv[1], O_RDONLY);
    close(STDOUT_FILENO);
    open(argv[2], O_WRONLY|O_CREAT, 0666);

    execlp("/bin/cat", "cat", NULL);
    err_exit("execlp error");
}

3.fcntl

int fcntl(int fd, F_DUPFD, ... /* arg */ );
//示例见下

fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );

操纵文件描述符, 改变已经打开的文件的属性

fcntl常用操作(cmd常用取值)

F_DUPFD (long)

复制文件描述符

F_GETFD (void)

F_SETFD (long)

文件描述符标志

F_GETFL (void)

F_SETFL (long)

文件状态标志

F_GETLK

F_SETLK,F_SETLKW(阻塞)

文件锁

//示例: 复制文件描述符
int main(int argc, char *argv[])
{
    int fd = open("text.txt", O_WRONLY|O_TRUNC);
    if (fd == -1)
        err_exit("open O_WRONLY error");

    close(1);   //将标准输出关闭, 则文件描述符1将空闲
    // 当cmd使用F_DUPFD时, 第三个参数代表搜索的起始位置
    int dupfd = fcntl(fd, F_DUPFD, 1);  // 1代表: 从1开始搜索一个空闲的文件描述符
    if (dupfd < 0)
        err_exit("fcntl F_DUPFD error");
    cout << "dupfd = " << dupfd << endl;
}

文件状态标志

F_GETFL (void)

Get the file access mode and the file status flags; arg is ignored.

F_SETFL (int)

Set the file status flags to  the  value  specified  by  arg.   File  access  mode(O_RDONLY,  O_WRONLY,  O_RDWR)  and  file  creation  flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) in arg are ignored.  On Linux this command can change only  the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.

//示例: 给文件描述符0设置成非阻塞模式
int main(int argc, char *argv[])
{
    int flags = fcntl(0, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get error");
    flags |= O_NONBLOCK;
    if (fcntl(0, F_SETFL, flags) == -1)
        err_exit("fcntl set error");

    char buf[BUFSIZ];
    if (read(0, buf, sizeof(buf)) == -1)
        err_exit("read STDIN_FILENO error");
    cout << "buffer size = " << strlen(buf) << endl;
    cout << buf << endl;
}
//示例: 文件状态设置与清除(函数封装)
void set_fl(int fd, int setFlag)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get flags error");
    //设置状态
    flags |= setFlag;
    if (fcntl(fd, F_SETFL, flags) == -1)
        err_exit("fcntl set flags error");
}
void clr_fl(int fd, int clrFlag)
{
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags == -1)
        err_exit("fcntl get flags error");
    //清除状态
    flags &= ~clrFlag;
    if (fcntl(fd, F_SETFL, flags) == -1)
        err_exit("fcntl set flags error");
}

//测试
int main(int argc, char *argv[])
{
    set_fl(0, O_NONBLOCK);
    clr_fl(0, O_NONBLOCK);
    char buf[BUFSIZ];
    if (read(0, buf, sizeof(buf)) == -1)
        err_exit("read STDIN_FILENO error");
    cout << "buffer size = " << strlen(buf) << endl;
    cout << buf << endl;
}

文件锁

F_SETLK (struct flock *)

Acquire  a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len  fields  of lock.   If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.

F_SETLKW (struct flock *) 如果加锁不成功:会一直阻塞直到解锁

As for F_SETLK, but if a conflicting lock is held on the file, then wait for  that lock to be released.  If a signal is caught while waiting, then the call is interrupted and (after the signal  handler  has  returned)  returns  immediately  (with return value -1 and errno set to EINTR; see signal(7)).

F_GETLK (struct flock *)

On  input  to this call, lock describes a lock we would like to place on the file.

If the lock could be placed, fcntl() does  not  actually  place  it,  but  returns F_UNLCK  in  the l_type field of lock and leaves the other fields of the structure unchanged.  If one or more  incompatible  locks  would  prevent  this  lock  being placed,  then  fcntl()  returns  details  about  one of these locks in the l_type, l_whence, l_start, and l_len fields of lock and sets l_pid to be the  PID  of  the process holding that lock.

//文件锁结构体
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) */
    ...
};

注意: Specifying 0 for l_len has the special meaning: lock all bytes starting  at

the  location  specified  by l_whence and l_start through to the end of file,

no matter how large the file grows.

//示例1
int main(int argc, char *argv[])
{
    int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd == -1)
        err_exit("open file error");

    struct flock lock;
    lock.l_type = F_WRLCK;  //设定独占锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0; //锁定全部文件

    //if (fcntl(fd, F_SETLK, &lock) == 0)   //对比下面
    if (fcntl(fd, F_SETLKW, &lock) == 0)
    {
        cout << "file lock success, press any key to unlock..." << endl;
        cin.get();

        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = 0;
        lock.l_len = 0;
        if (fcntl(fd, F_SETLK, &lock) == -1)
            err_exit("file unlock error");
        else
            cout << "file unlock success" << endl;
    }
    else
        err_exit("file lock error");
}
//示例2: 打印加锁进程号
int main(int argc, char *argv[])
{
    int fd = open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd == -1)
        err_exit("open file error");

    struct flock lock;
    lock.l_type = F_WRLCK;  //设定独占锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0; //锁定全部文件

    if (fcntl(fd, F_SETLK, &lock) == 0)
    {
        cout << "file lock success, press any key to unlock..." << endl;
        cin.get();

        lock.l_type = F_UNLCK;
        lock.l_whence = SEEK_SET;
        lock.l_start = 0;
        lock.l_len = 0;
        if (fcntl(fd, F_SETLK, &lock) == -1)
            err_exit("file unlock error");
        else
            cout << "file unlock success" << endl;
    }
    else    //如果失败, 则获取锁信息
    {
        if (fcntl(fd, F_GETLK, &lock) == -1)
            err_exit("get lock error");

        cout << "lock process: " << lock.l_pid << endl;
        if (lock.l_type == F_WRLCK)
            cout << "type: F_WRLCK" << endl;
        else
            cout << "type: F_RDLCK" << endl;

        if (lock.l_whence == SEEK_SET)
            cout << "whence: SEEK_SET" << endl;
        else if (lock.l_whence == SEEK_END)
            cout << "whence: SEEK_END" << endl;
        else
            cout << "whence: SEEK_CUR" << endl;
    }
}

文件I/O实践(3) --文件共享与fcntl的更多相关文章

  1. 文件操作篇 close creat dup dup2 fcntl flock fsync lseek mkstemp open read sync write

    文件操作篇 close creat dup dup2 fcntl flock fsync lseek mkstemp open read sync write close(关闭文件) 相关函数 ope ...

  2. APUE学习笔记——3.文件共享与fcntl介绍

    基本概念 内核使用3个数据结构描述一个打开的文件:进程表.文件表.V节点表 首先了解3种数据结构的概念     1 进程表         每一个进程有一个进程表.进程表里是一组打开的文件描述符,如标 ...

  3. vue 单文件组件最佳实践

    vue 单文件组件最佳实践 生命周期 template <template> <section> <h1>vue single file components te ...

  4. linux系统编程之文件与IO(八):文件描述符相关操作-dup,dup2,fcntl

    本节目标: 1,文件共享 打开文件内核数据结构 一个进程两次打开同一个文件 两个进程打开同一个文件 2,复制文件描述符(dup.dup2.fcntl) 一,文件共享 1,一个进程打开两个文件内核数据结 ...

  5. 阿里云NAS文件迁移项目实践

    阿里云文件存储NAS是阿里云推出的用于传统文件共享的,使用NFS协议挂载的共享文件夹. 产品背景 下图是NAS和阿里云另一明星产品OSS以及块存储EBS的区别 NAS核心优势:无需修改程序,挂载之后, ...

  6. 文件I/O实践(2) --文件stat

    功能:获取文件元数据 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int st ...

  7. 文件I/O实践(1) --基础API

    什么是I/O 输入/输出是内存和外设之间拷贝数据的过程: 设备->内存: 输入操作 内存->设备: 输出操作 高级I/O: ANSI C提供的标准I/O库函数成为高级I/O, 也称为带缓冲 ...

  8. 《linux就该这么学》课堂笔记15 vsftpd文件传输、Samba/NFS文件共享

    1.为了能够在如此复杂多样的设备之间(Windows.Linux.UNIX.Mac等不同的操作系统)解决问题解决文件传输问题,文件传输协议(FTP)应运而生. FTP服务器是按照FTP协议在互联网上提 ...

  9. ASP.NET Core文件压缩最佳实践

    前言 在微软官方文档中,未明确指出文件压缩功能的使用误区. 本文将对 ASP.NET Core 文件响应压缩的常见使用误区做出说明. 误区1:未使用 Brotil 压缩 几乎不需要任何额外的代价,Br ...

随机推荐

  1. AnyConnect使用说明(电脑版Windows)

    一.下载客户端 Anyconnect支持Windows.Mac电脑. 二.安装 1.双击打开下载的文件,点“Next”开始安装. 2.选择“I accept …”,再点下一步. 3.点“Install ...

  2. Appium--入门demo

    Appium环境搭建已经在在博客中写出 http://www.cnblogs.com/feimaoyuzhubaobao/p/5057832.html   那么本篇博客主要介绍java版本的appiu ...

  3. Elastic-Job——分布式定时任务框架

    摘要: Elastic-Job是ddframe中dd-job的作业模块中分离出来的分布式弹性作业框架.去掉了和dd-job中的监控和ddframe接入规范部分.该项目基于成熟的开源产品Quartz和Z ...

  4. 潜谈IT从业人员在传统IT和互联网之间的择业问题(上)-传统乙方形公司

    外包能去吗?项目型公司如何?甲方比乙方好?互联网公司就一定好吗? 相信许多从业者在经历了3-5年的工作期后都会带着这样的疑问或者疑惑. 2012年-2014年间,曾经面试过500人,亲身面试的也有15 ...

  5. Android通知Notification全面剖析

    通知 通知是您可以在应用的常规 UI 外部向用户显示的消息.当您告知系统发出通知时,它将先以图标的形式显示在通知区域中.用户可以打开抽屉式通知栏查看通知的详细信息. 通知区域和抽屉式通知栏均是由系统控 ...

  6. Android图表库MPAndroidChart(十二)——来点不一样的,正负堆叠条形图

    Android图表库MPAndroidChart(十二)--来点不一样的,正负堆叠条形图 接上篇,今天要说的,和上篇的类似,只是方向是有相反的两面,我们先看下效果 实际上这样就导致了我们的代码是比较类 ...

  7. SpringMVC常用配置

    关于Spring.SpringMVC我们前面几篇博客都介绍了很多,但是还不够,这些框架中涉及到的注解.配置非常多,那么我们今天再来介绍一个SpringMVC的基本配置,灵活的使用这些配置,可以让我们在 ...

  8. FORM开发之说明性弹性域开发

    1.注册使用弹性域的表,字段 注册表语法:ad_dd.register_table('所有者','表名','T自动扩展/S非自动扩展','下一区','自由','已使用') AD_DD.REGISTER ...

  9. Android事件分发回传机制

    转载本博客,请注明出处:点击打开链接   http://blog.csdn.net/qq_32059827/article/details/52489026 之前以一个爷爷给孙子分馒头的故事,初探了安 ...

  10. Shell脚本编程入门(一)

    最近在学shell,记录一下. if语句的使用: 1.判断两个参数大小 #!/bin/sh #a test about if statement a=10 b=20 if [ $a -eq $b ]; ...