zoukankan      html  css  js  c++  java
  • linux 之文件基础 (二)、文件IO API

    1. 操作文件的重要性

    由于linux的一切皆文件的概念,因此,学会如何操作文件是非常重要的。对于操作文件,我们需要掌握以下内容:

    • 基本的文件操作: 以特定的权限打开文件、关闭文件、向文件读写等。
    • 操作文件的属性:获取属性、改变属性等。
    • 对于目录文件的操作

    上述的每一类操作都有对应的API。 下面我们分别介绍各种API

    2. 文件基本操作之 文件IO

    2.1 文件IO 简介

    文件IO,是Linux上操作文件的两套API集合之一,另外一套API是标准IO。二者的区别是是否自带缓冲。“没有自带缓存的I/O”就是文件IO。需要注意,文件IO的API 属于系统调用,因此在查看帮助手册时应该查第2分册。

    2.2 文件IO之打开文件 open 函数

    #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);
    int creat(const char *pathname, mode_t mode);
    

    2.2.1函数参数

    (1)pathname : 需要打开文件的文件名
    (2)flags : 打开方式,可选方式有以下几种

    • O_RDONLY:只读方式打开文件。
    • O_WRONLY:可写方式打开文件。
    • O_RDWR:读写方式打开文件。
    • O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设置权限(读写执行权限)。
    • O_EXCL:如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。
    • O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据。
    • O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行write写文件默认从开始位置开始写,加了这个参数以后从文件末尾开始写。

    (3)mode : 指定文件权限 也可以用宏实现

    • S_IRWXU 00700 user (file owner) has read, write, and execute
      permission
    • S_IRUSR 00400 user has read permission
    • S_IWUSR 00200 user has write permission
    • S_IXUSR 00100 user has execute permission
    • S_IRWXG 00070 group has read, write, and execute permission

    2.2.2 函数返回值:

    • 成功:返回文件描述符
    • 失败:-1

    2.2.3 使用举例子

    在这里插入图片描述

    open 不能创建 设备文件,只能创建普通文件。

    int creat(const char *pathname, mode_t mode);
    等价于open(pathname, O_CREAT|O_WRONLY|O_TRUNC, mode)

    2.3 关闭文件

    2.3.1 close 函数原型

    #include <unistd.h>
    int close(int fildes);
    

    2.3.2 函数参数:

    • fildes : 需要关闭文件的文件描述符

    2.3.3 返回值:

    • 成功 0
    • 失败 -1

    注意:由于一个进程只能打开1024 个文件描述符,因此,不用的文件应该及时的关闭。
    当一个进程终止时,内核会将打开的所有的文件描述符关闭。
    释放一个文件的同时,也释放该进程在该文件上的所有记录锁。

    2.4 文件IO 之读文件

    2.4.1 read 函数原型

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
    

    函数功能:
    从一个已经打开的文件中读取内容

    2.4.2 函数参数

    fd : 文件描述符
    buf : 用来存放读到的内容的缓冲区首地址
    count :读取的字节数

    2.4.3 返回值

    成功: 返回实际读取的字节数(0 读到文件末尾)
    失败: -1 并设置errno

    2.5 写函数

    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);
    

    函数功能:
    向已经打开的文件中写内容

    2.5.1函数参数:

    fd : 文件描述符
    buf : 写缓冲缓冲区首地址
    count : 指定写入的字节数

    2.5.2 返回值:

    • 成功:实际写到文件的字节数
    • 失败:-1

    注意:

    • 写文件出现错误的原因通常是,磁盘已满、或者文件长度超过了一个进程文件长度限制。
    • 对于普通文件,写操作从当前文件偏移量开始
    • 在打开文件时,如果指定了O_APPEND 参数,那么执行写操作从文件末尾追加。

    2.5 文件定位函数

    #include <sys/types.h>
    #include <unistd.h>
    off_t lseek(int fd, off_t offset, int whence);
    

    函数功能:文件定位。 实际上就是调整文件内部的指针的,在读和写的时候,每读一个或者写一个字节,文件指针就会自动向后移动一个。

    2.5.1 函数参数:

    (1)fd:文件描述符
    (2)offset:相对于偏移量偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(对应:向前移,向后移
    (3)whence: 基准点。可选项有一下几个

    • SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小。
    • SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量。
    • SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小。

    2.5.2 返回值:

    • 失败 :-1
    • 成功:当前文件的偏移量(当前读写位置相对文件开始位置的字节数)通过lseek计算文件的大小

    注意:

    • buf 需要调用者自己来分配内存,使用后,由调用者自己释放。
    • 读操作从文件的当前偏移量开始,在读成功返回前,读多少字节,将稳健偏移量加多少。
    • 向前偏移不可以偏移超过文件的头
    • 向后偏移,如果超过了文件的尾,那么会形成文件空洞。
    • 空洞文件和真实文件的区别在于磁盘的使用情况 。通过du -sh 文件名可以 查看空洞文件和真实文件的区别,这个命令显示文件真实使用了多少的磁盘空间。

    空洞文件的作用:

    空洞技术非常有用。例如迅雷下载一个3G的电影,当我们点击下载后,会发现下载的目录里面会多出一个3G的文件,这3G文件实际上就是空洞文件。意思是迅雷先占了3G的空间。后面下载的内容往空洞里面填。

    3. 文件IO练习

    3.1 打开一个文件

    /*
    以0644 权限 打开test.txt 文件,如果文件不存在则创建文件,如果文件存在则截短文件内容。
    */
    #include<stdio.h>                                                                                                                              
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main()
    {
        int fd = open("test.txt",O_WRONLY | O_CREAT | O_TRUNC,0644);
        if(fd == -1) 
        {   
            perror("open file error");
        }   
        return 0;
    }
    

    3.2 计算一个文件中有多少个字符

    #include<stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    /*
     *读一个文件打印,并计算一个文件中有多少个字符。
     * */
    int
    main()
    {
        int fd = open("file.txt",O_RDONLY,0666);
        if(fd == -1) 
        {   
            perror("open file error");
            return -1; 
        }   
        char read_buf[128];
        int count = 0;
        int sum = 0;
        while((count = read(fd,read_buf,5))>0)
        {   if(count != 5)
            {   
                read_buf[count] = '';// 如果count 不等于5, 则需要把第count个字符以后的缓冲区清空。
            }   
            printf("%s",read_buf);
            sum += count;
        }   
        printf("一共%d个字符
    ",sum);
        close(fd);
        return 0;
    }   
    

    3.3 实现简单的cp 命令

    /*                                                                                                                                             
     *cp file1 file2  将file1 的内容拷贝到file2 中, file1  file2 由命令行指定
     * */
    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main( int argc , const char * argv[])
    {
        if(argc != 3)
        {
            perror(" 参数错误 ");
            return -1;
        }
        //打开文件1
        int file1_fd = open(argv[1],O_RDONLY,0666);
        if(file1_fd == -1)
        {
            perror("open file1 error");
            return -1;
        }
        //打开文件2,如果文件2 不存在,则新创建一个,如果已经存在则截断
        int file2_fd = open(argv[2],O_RDWR | O_CREAT | O_TRUNC,0666);
        if(file1_fd == -1)
        {
            perror("open file2 error");
            return -1;
        }
        char buf[128] = "";
        int readCount;
        while((readCount = read(file1_fd,buf,5)) > 0)
        {
            write(file2_fd,buf,readCount);
        }
        close(file2_fd);
        close(file1_fd);
        return 0;
    }   
    

    查看两个文件内容是否一致命令:
    diff -s file1 file2

  • 相关阅读:
    Java运行时内存
    java --对象流与对象的序列化
    Java 文件操作
    爬虫
    eclipse项目放到github
    越来越玄的JAVA
    map和set的遍历
    集合总览
    unsafe类
    狡诈的java并发容器
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764121.html
Copyright © 2011-2022 走看看