Unix高级编程:文件的基本操作、mmap将文件映射虚拟地址、文件描述符的复制

本文主要是介绍Unix高级编程:文件的基本操作、mmap将文件映射虚拟地址、文件描述符的复制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、文件的基本操作
"open"(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags,...); //正确写法,真正原型
以写入的方式打开文件,如果文件不存在,则创建文件,指定文件的权限为 664
open(filename, O_RDWR|O_CREAT|O_TRUNC, mode); //mode 0664
/*代码参见 file1.c */ "优先代码框架"
#include <stdio.h>
#include <unistd.h> //close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
    int fd;
    int flags = O_RDWR|O_CREAT|O_TRUNC;
    //打开文件
    fd = open("filename", flags, 0664);
    if(fd == -1) {
        perror("open");
        return 1;
    }
    printf("open success...\n");
    //关闭文件
    close(fd);
    return 0;
}


补充:
1)"文件权限"
[d][rwx][rwx][rwx]   2   tarena  tarena  4096 12月4 11:40 mmap.c
[1][234][567][890] 节点 | 拥有人 | 群组 | 大小 | 修改日期 | 文件名


[1] 文件类型
"d" 目录directory
"-" 文件file
"l" 链接文件link file
"s" 通讯文件socket
"p" 管道文件
"b" 区块设备文件,文件里可供存储的接口设备block
"c" 字符设备文件,串行端口设备,如键盘、鼠标character
 
"rwxrwxrwx" 有权限有字母,无权限为"-"
[234]:属主("u")user
[567]:属组("g")group
[890]:其他人("o")other
[2~0]:所有人("a")all
权限更改:
chgrp :改变档案所属群组,格式:chgrp [-R] tarena hello.c
chown :改变档案所属人,格式:chown [-R] users hello.c
chmod :改变档案的属性,格式:chmod [-R] rwx 档案或目录
"chmod" change mode 改变权限
使用chmod让所有人拥有执行权限格式:"chmod a+x (文件名)"//固定格式类推
使用chmod让其他人去除执行权限格式:"chmod o-x (文件名)"//固定格式类推
权限更改:八进制数字 r:4 w:2 x:1
 "chmod 664 (文件名)"
rw-rw-r-- 0664 (210210210 二进制次方)
rwxr-xr-x 0755 (0代表普通权限,不用考虑)
u +(加入) r
chmod g -(除去) w 档案/目录
o =(设定) x
a






2)"权限掩码" //指定创建文件的时候,所要拿掉的权限,即权限掩码
获取权限掩码:"umask" 0002 -------w- 对应 -rw-rw-r-- //默认创建无x
更改umask:umask 0033 ----wx-wx 对应 -rw-r--r--
"touch file1" 
-rw-rw-r-- 1 tarena tarena 0 12月 5 09:57 file1


"tarena"(1)这个文件归谁所有————属主("u")
"tarena"(2)属主指定的组————属组("g")


"close"(2)
(上次笔记)


"read"(2)
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:从fd指定的文件描述符读取内容
参数:
"fd" open(2)的返回值,指定了要从这个文件描述符里读取
"buf" 存储读取内容空间的首地址
"conunt" 本次读取的最大字节数
返回值:
成功 - 返回读取的字节数(也会比count小),0 代表读取到了文件的末尾
失败 - 返回 -1 ,errno被设置
/*举例验证文件读取,代码参见 mycat.c */
#include <stdio.h>
#include <unistd.h> //close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h> //bzero
int main(int argc, char *argv[]) {
    int fd, size;
    char arr[128] = {0};
    int flags = O_RDWR;
    fd = open(argv[1], flags);
    if(fd == -1) {
        perror("open");
        return 1;
    }   
    printf("open success...\n");
    bzero(arr, 128); //把arr开始的地址对应数据全部设置为0
    while((size = read(fd, arr, 127)) > 0) {
        printf("%s", arr);
        bzero(arr, 128); //把arr开始的地址对应数据全部设置为0
    }   
    printf("read success...\n");
    close(fd);
    return 0;
}
gcc mycat.c -o mycat
sudo mv mycat /bin //将mycat程序在任何路径下都可以实现命令行执行其功能
sudo mv /bin/mycat . //将mycat程序移出到当前目录下


"write"(2)
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:向fd指定的文件描述符写入内容
参数:
"fd" open(2)的返回值,指定了要写入文件的描述符
"buf" 从buf指定地址的空间里读取数据
"count" 最多向文件中写入的字节数
返回值:
成功 - 返回实际写入文件的字节数(也会比count小),0 代表没有内容被写入了
失败 - 返回 -1,errno被设置
/*举例验证文件写入,代码参见 write.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(void) {
    char buf[128] = "hello,world!welcome!";
    int fd = open("file1.c", O_WRONLY|O_CREAT|O_TRUNC, 0664);
    if(fd == -1) {
        perror("open");
        return 1;
    }   
    write(fd, buf, strlen(buf)); //写入有效字符个数
    close(fd);
    return 0;
}


0 标准输入 STDIN_FILENO
1 标准输出 STDOUT_FILENO
2 标准错误输出 STDERR_FILENO


"lseek"(2)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:重新设置文件读写的位置
参数:
"fd" 指定了文件。open(2)的返回值
"offset" 相对与位置的偏移字节数
"whence" 
SEEK_SET 文件的头部
SEEK_CUR 文件的当前位置
SEEK_END 文件的尾部
返回值:
成功 - 返回相对文件头的字节数
失败 - 返回 -1,errno被设置
/*举例验证lseek的使用,代码参见 lseek.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
    int fd; 
    char buf;
    fd = open("aaa.txt", O_RDWR); //aaa.txt内容:tarenaesd1610
    if(fd == -1) {
        perror("open");
        return 1;
    }   
    //要直接读取出第7个字符
    lseek(fd, 6, SEEK_SET);
    int r = read(fd, &buf, 1); 
    write(1, &buf, r); //1 == STDOUT_FILENO
    write(STDOUT_FILENO, "\n", 2); //\n是字符串,包含\0,c
    off_t var_f = lseek(fd, 0, SEEK_CUR);//获取当前读写位置
    printf("%lu\n", var_f); //无符号长整形 7
    close(fd);
    return 0;
}




二、使用mmap将文件直接映射到进程的虚拟地址空间里,然后在内存里更新文件内容,直接反映到文件里
MAP_SHARED 对内存的操作反映的文件里
MAP_PRIVATE 只对内存操作,不反映到文件里
命令行:"od -tx1 -tc aaa.txt" //显示文件当中的偏移量及ASCII码
0000000  74  61  72  65  6e  61  0a
          t   a   r   e   n   a  \n
0000007
/*举例验证,代码参考 mmap_file.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main(void) {
    //以读写方式打开文件aaa.txt
    int fd = open("aaa.txt", O_RDWR);
    if(fd == -1) {
        perror("open");
        return 1;
    }   
    //将文件映射到进程的虚拟地址空间里
    void *p = mmap(NULL,6,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    if(p == MAP_FAILED) { //映射失败
        perror("mmap");
        return 2;
    }   
    printf("mmap success...\n");
    close(fd);
    int *q = p; //类型转换
    q[0] = 0x30313233; //十六进制转换为十进制的数,就是ASCII码
    munmap(p, 6); //解除映射
    return 0;
}


命令行:"od -tx1 -tc aaa.txt" 
0000000  33  32  31  30  6e  61  0a
          3   2   1   0   n   a  \n
0000007




三、文件描述符的复制
"文件重定向"
使用文件描述符的复制,可以改变进程的输入源或输出目的文件。
这样就改变的文件流的流向,这就是文件的输入/输出(I/O)"重定向"。
输入重定向
输出重定向
《鸟哥linux私房菜》——晚自习:专门看这块儿内容。


"dup"(2)
#include <unistd.h>
int dup(int oldfd);
功能:复制一个文件描述符
参数:"oldfd" 源描述符
返回值:
成功 - 返回一个新的文件描述符,未被使用的、最小的数字
失败 - 返回 -1,errno被设置


"dup2"(2)
int dup2(int oldfd, int newfd);
功能:复制一个新的文件描述符
参数:
"oldfd" 旧的文件描述符
"newfd" 新的文件描述符
返回值:
成功 - 返回一个新的文件描述符,未被使用的、最小的数字
失败 - 返回 -1,errno被设置


/*举例说明文件描述符的复制,代码参见 dup.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void) {
    int fd, s_fd;
    char msg[20] = "hello,world!";
    fd = open("hello", O_RDWR|O_CREAT, 0664); //fd(hello)->3
    if(fd == -1) {
        perror("open");
        return 1;
    } //s_fd(临时)->4
    s_fd = dup(1); //STDOUT_FILENO->4
    dup2(fd, 1); //fd(hello)->1
    close(fd); //3不被使用,不再指向hello
    write(1, msg, strlen(msg));
    printf("\n");
    dup2(s_fd, 1); //STDOUT_FILENO->1,回原位,hello无指向,释放
    write(1, msg, strlen(msg));
    write(1, "\n", 2);
    close(s_fd); //4不被使用,不再指向STDOUT_FILENO
    return 0;
}



cp 源文件 目标文件 (不要求拷贝文件夹,仅文件即可)
使用今天的open/read/write编写程序完成cp命令的功能,生成可执行文件mycp
/*库函数实现:代码*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
    FILE *p_old, *p_new;
    int size = 0;
    char buf[128] = {0};
    p_old = fopen(argv[1], "rb");
    if(!p_old) {
        printf("文件打开失败!\n");
        return 1;
    }   
    p_new = fopen(argv[2], "wb");
    if(!p_new) {
        printf("文件打开失败!\n");
        fclose(p_old);
        p_old = NULL;
        return 2;
    }   
    while(1) {
        size = fread(buf, sizeof(char), 128, p_old);
        fwrite(buf, sizeof(char), size, p_new);
        if(!size) {
            break;
        }   
    }   
    fclose(p_old);
    p_old = NULL;
    fclose(p_new);
    p_new = NULL;
    return 0;
}
/*系统调用函数实现:代码*/  "老王标准答案"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
function: 实现文件内容的拷贝
parameter:
s 源文件描述符
d 目标文件描述符
return value:
void
author:Jan
date:2016.12.07
*/
void copy_file(int s, int d) {
    char buf[128];
    int r, w;
    char *tmp;
    while((r = read(s, buf, 128)) > 0) {
        tmp = buf;
        while(1) { //将一次读出的内容,完全写入
            w = write(d, tmp, r); //w实际写入可能会比r小
            r = r - w; //未写入内容的字节数
            if(!r) {
                break;
            }   
            tmp += w; //tmp往后挪
        }   
    }   
    return;
}
int main(int argc, char *argv[]) {
    int s_fd, d_fd;
    s_fd = open(argv[1], O_RDONLY);
    if(s_fd == -1) {
        perror("open source");
        return 1;
    }   
    d_fd = open(argv[2], O_RDWR|O_CREAT, 0664);
    if(d_fd == -1) {
        perror("open dest");
        close(s_fd);
        return 2;
    } //文件内容拷贝:
    copy_file(s_fd, d_fd);
    close(s_fd);
    close(d_fd);
    return 0;
}

这篇关于Unix高级编程:文件的基本操作、mmap将文件映射虚拟地址、文件描述符的复制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/541371

相关文章

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

postgresql数据库基本操作及命令详解

《postgresql数据库基本操作及命令详解》本文介绍了PostgreSQL数据库的基础操作,包括连接、创建、查看数据库,表的增删改查、索引管理、备份恢复及退出命令,适用于数据库管理和开发实践,感兴... 目录1. 连接 PostgreSQL 数据库2. 创建数据库3. 查看当前数据库4. 查看所有数据库

Java中的for循环高级用法

《Java中的for循环高级用法》本文系统解析Java中传统、增强型for循环、StreamAPI及并行流的实现原理与性能差异,并通过大量代码示例展示实际开发中的最佳实践,感兴趣的朋友一起看看吧... 目录前言一、基础篇:传统for循环1.1 标准语法结构1.2 典型应用场景二、进阶篇:增强型for循环2.

使用Python进行GRPC和Dubbo协议的高级测试

《使用Python进行GRPC和Dubbo协议的高级测试》GRPC(GoogleRemoteProcedureCall)是一种高性能、开源的远程过程调用(RPC)框架,Dubbo是一种高性能的分布式服... 目录01 GRPC测试安装gRPC编写.proto文件实现服务02 Dubbo测试1. 安装Dubb

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Linux使用scp进行远程目录文件复制的详细步骤和示例

《Linux使用scp进行远程目录文件复制的详细步骤和示例》在Linux系统中,scp(安全复制协议)是一个使用SSH(安全外壳协议)进行文件和目录安全传输的命令,它允许在远程主机之间复制文件和目录,... 目录1. 什么是scp?2. 语法3. 示例示例 1: 复制本地目录到远程主机示例 2: 复制远程主

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa