3.文件读写细节及文件管理


3.1.errno和perror
(1)errno(error_number即错误号码),linux系统中对各种常见错误做了编号表,当函数执行错误时,函数会返回1个特定的errno编号来告诉我们该函数到底哪里错了(前提是该函数返回时会设置errno);errno是由OS来维护的1个全局变量,任何OS内部函数都可以通过设置errno来告诉上层调用者究竟刚才发生了1个什么错误。
(2)errno本身实质是1个int类型的数字,每个数字编号对应1种错误,当我们只看errno时只能得到1个错误编号数字(譬如-37);linux系统提供了1个函数perror(print_error),perror函数内部会读取errno并且将其直接转成对应的错误信息字符串,然后print打印出来。


3.2.read和write的count
(1)count和返回值的关系;count参数表示我们想要写或者读的字节数,返回值表示实际完成的要写或者读的字节数;实际的有可能等于想要读写的,也有可能小于(说明没完成任务)。
(2)count再和阻塞非阻塞结合起来,就会更加复杂,如果某个函数是阻塞式的,则我们要读取30个字节数据,结果暂时只有20个字节数据时就会被阻塞住,等待剩余的10个字节数据可以读。
(3)有时候我们写正式程序时,我们要读取或者写入的是1个很庞大的文件(譬如文件有2MB),我们不可能把count设置为2*1024*1024,而应该去把count设置为1个合适的数字(譬如2048、4096),然后通过多次读取来实现全部读完。


3.3.文件IO效率和标准IO
(1)文件IO即由open、close、write、read等API函数构成的1套用来读写文件的体系,这套体系可以很好的完成文件读写,但是效率并不是最高的;应用层C语言库函数提供了一些用来做文件读写的函数列表,叫标准IO,标准IO由一系列的C库函数构成(fopen、fclose、fwrite、fread),这些标准IO函数是由文件IO封装而来的(fopen内部其实调用的还是open)。
(2)标准IO加了封装之后主要是为了在应用层添加1个缓冲机制,这样我们通过fwrite写入的内容不是直接进入内核中的buf,而是先进入应用层标准IO库自己维护的buf中,然后标准IO库自己根据操作系统单次write的最佳count来选择好的时机来完成write到内核中的buf,内核中的buf再根据硬盘的特性来选择好的实际去最终写入硬盘中。


3.4.静态文件和inode节点
(1)文件平时都存放在硬盘中,硬盘中存储的文件以1种固定的方式存放,其被称为静态文件。
(2)1块硬盘区域可分为2块区域,1块是硬盘内容管理表项,1块是真正存储内容的区域;操作系统最初手里的信息是文件名,最终得到的是文件内容;操作系统访问文件时首先读取硬盘内容管理表,从中找到目标文件的扇区级别的信息,然后利用该信息去查询真正存储内容的区域,最后得到我们要的文件内容。
(3)硬盘内容管理表中以文件为单位记录了各个文件的各种信息,每个文件都有1个信息列表(即inode,i节点,其实质是1个结构体,该结构体中有很多元素,每个元素记录了该文件的一些信息,包括文件名、文件在硬盘上对应的扇区号、块号…);硬盘资源管理是以文件为单位进行的,每个文件对应1个inode,每个inode对应1个数字编号,每个数字编号对应1个结构体,结构体中记录了该文件的各种信息。
(4)联系平时实践,大家格式化硬盘(U盘)时发现有快速格式化和底层格式化两个选项;快速格式化非常快,格式化1个32GB的U盘只要1秒钟,普通格式化格式化速度慢;快速格式化就是只删除了U盘中的硬盘内容管理表(即inode),真正存储的内容没有动,这种格式化的内容是有可能被找回的。


3.5.动态文件和vnode节点
(1)1个程序的运行就是1个进程,我们在程序中打开的文件就属于某个进程;每个进程都有1个数据结构用来记录该进程的所有信息(即进程表);进程表中有1个指针会指向1个数据结构(即文件描述符表,每个文件描述符表项=fd+相对应的文件表指针),文件描述符表记录了当前进程打开的所有文件的fd及其相对应的文件表指针;文件表指针指向1个数据结构(即文件表,每个文件表=文件状态标志+当前文件位移量即文件指针+V节点指针(指向vnode节点))文件表中记录了与某个fd相对应的文件相关信息;文件描述符表中用来索引各个打开的文件的index就是文件描述符fd(fd->文件表指针->文件表->V节点指针->vnode节点)。
(2)1个vnode中就记录了1个被打开的文件的各种信息(V节点=i节点信息+当前文件长度+对不同种类文件操作的给个函数指针),则我们只要知道该文件的fd,就可以找到该文件的vnode进而对这个文件进行各种操作。


3.6.文件和流的概念
(1)流(stream)对应自然界的水流,在文件操作中,文件类似是1个大包裹,里面装了1堆字符,但文件被读出/写入时都只能1个字符1个字符的进行,而不能1股脑儿的读写,则1个文件中N多的个字符被挨个依次读出/写入时,这些字符就构成了1个字符流。
(2)流这个概念是动态的,不是静态的;编程中提到流这个概念,一般都是IO相关的,所以经常叫IO流;文件操作时就构成了1个IO流。


3.perror
/*
 * 公司:XXXX
 * 作者:Rston
 * 博客:http://blog.csdn.net/rston
 * GitHub:https://github.com/rston
 * 项目:文件读写细节及文件管理
 * 功能:演示perror函数的使用。
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int fd = -1;                                // fd即file descriptor,文件描述符     
    int ret = -1;                               // 用于接收read返回值,判断是否读文件成功
    char buf[100] = {0};                        // 构建缓冲区存放从文件读出的内容
    char bufwrite[20] = "linux is great";       // 构建缓冲区存放要写入文件的内容

    // 打开test.txt文件,若该文件不存在则创建(权限666),若该文件存在则报错
    fd = open("test.txt", O_RDWR | O_CREAT | O_EXCL, 0666);             
    if (-1 == fd)                               // 判断文件打开是否成功,也可这样写if (fd < 0)
    {
        //printf("open file error.\n");
        perror("open file error");              // 通过perror捕捉errno错误信息并打印输出
        //return -1;                            // 使用return或exit退出进程或程序
        exit(-1);
    }
    else
    {
        printf("open file sucess. fd = %d.\n", fd);
    }

#if 1   
    ret = write(fd, bufwrite, strlen(bufwrite));    // 写内容到文件中
    if (ret < 0)                                    // 判断内容是否成功写入文件
    {
        //printf("write file errot.\n");
        perror("write file errot");
        //return -1;
        exit(-1);
    }
    else
    {
        printf("write %d bytes to file.\n", ret);
        printf("the content of write is [%s].\n", bufwrite);
    }
#endif

#if 1   
    ret = read(fd, buf, sizeof(buf));   // 读取文件内容
    if (ret < 0)                        // 判断读取文件是否成功
    {
        //printf("read file error.\n");
        perror("read file error");
        //return -1;
        exit(-1);
    }
    else
    {
        printf("read %d bytes actual from file.\n", ret);
        printf("the content of read is [%s].\n", buf);
    }
#endif

    close(fd);                          // 关闭文件

    //return 0;
    exit(0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值