TLPI(liunx/unix系统编程手册)笔记(三) 文件IO:通用的IO模型

读下来总的就是介绍了四个IO的API--open,read,write,close。

大家都是知道的,everything is file,在linux系统里面一切都是看作文件来操作的,学习linux就得先学好文件IO,也可以看见TLPI这本书的介绍完一些概念之后就开始介绍文件IO了。

IO,大概的分为磁盘文件IO,buffering(缓冲)IO。貌似缓冲的水很深,之后会写博客。

————————————————————————————————————

(1)文件描述符。

  在进行IO操作之前,总要先打开吧,open函数打开文件并返回一个非负整数,这个数就说我们所说的文件描述符。在shell中0,1,2已经被占领,而且这三个描述符总是打开的,书中提到最好是把0,1,2这种描述放大改了,遵循POSIX,0---STDIN_FILENO,1---STDOUT_FILENO,2---STDERR_FILENO。但是freopen会使这三个标准变化,就是说不一定是012了。

(2)函数。

  <1>.open

SYNOPSIS
       #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);

  pathname就是路径,如果是符号链接的话会自动分解。

  flags是访问模式,为位掩码,但是这里值得注意的是,O_RDONLY | O_WRONLY 和 O_RDWR 是不一样的,原因是这三个宏是用012代替的,或运算的话逻辑上就会有错误。还有一些常用的O_APPEND文件尾追加数据,O_CREAT不存在时候创建,O_TRUNC清空文件。

  mode就是访问权限。下面是umask表可以用 | 。(例如S_IRUSR,R--read,USR用户组,很好记忆,记不得的时候就man)

              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

              S_IRGRP  00040 group has read permission

              S_IWGRP  00020 group has write permission

              S_IXGRP  00010 group has execute permission

              S_IRWXO  00007 others have read, write and execute permission

              S_IROTH  00004 others have read permission

              S_IWOTH  00002 others have write permission

              S_IXOTH  00001 others have execute permission

  <2>read.

SYNOPSIS
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

    ssize_t (signed size type),当然fd可以是STDIN_FILENO,这样就可以类似于gets()函数。

  <3>write用法和read差不多。

  <4>close. 

    close的错误检查是一定要有的。关闭一个未打开的文件描述符和重复关闭同一个文件描述符都是有可能的。书上指出可能会在NFS文件系统中出现。

  <5>lseek.   

      #include <sys/types.h>
       #include <unistd.h>

       off_t lseek(int fd, off_t offset, int whence);

   

    The lseek() function repositions the offset of the open file associated with the file descriptor fd to the argument offset according to thedirective whence as follows:

  SEEK_SET
  The offset is set to offset bytes.开始的地方

  SEEK_CUR
  The offset is set to its current location plus offset bytes.当下位置

  SEEK_END
  The offset is set to the size of the file plus offset bytes.末尾

    offset是从文件开始计算的。

文件空洞:

  就是lseek在可以在末尾之后添加字符,理应以0字符作为填充,但是和0字符填充的文件不一样,有文件空洞的文件在磁盘占有上面和没有空洞的是一样的,但是文件大小是会小,并不是以0字符填充的。网上查阅了相关资料,文件空洞是给内核说占有磁盘空间的。

  为了验证自己的想法,做了一些测试:

#include"tlpi_hdr.h"
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

#define OFFSET 4096*1000
int main()
{
    int openFd_test1;
    int openFd_test2;
    off_t offset;
    char buf[] = "flie_hole";
    int lenthOfBuf = sizeof(buf);
    char buf_zero[OFFSET]={0};

    mode_t modePerms = S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH;//rw-rw-rw-
    /*create two files for test*/
    openFd_test1 = open("test1", O_RDWR | O_CREAT | O_TRUNC, modePerms);
    openFd_test2 = open("test2", O_RDWR | O_CREAT | O_TRUNC, modePerms);
    if(openFd_test1 == -1 || openFd_test2 == -1)
        errExit("open");
    /*test1    --have file hole*/
    write(openFd_test1,buf,lenthOfBuf);
    offset = lseek(openFd_test1, OFFSET,SEEK_END);
    write(openFd_test1,buf,lenthOfBuf);
    /*test2    --haven‘t file hole*/
    write(openFd_test2,buf,lenthOfBuf);
    write(openFd_test2,buf_zero,OFFSET);
    write(openFd_test2,buf,lenthOfBuf);
    /*close two fd*/
    if(close(openFd_test1) == -1)
        errExit("close");
    if(close(openFd_test2) == -1)
        errExit("close");
    return 0;
}

  创建两个文件,test1用文件空洞,作为对比test2用0填充。我的电脑上的块大小是4096B

-rw-rw-r-- 1 aaron aaron 4096020 May 13 11:52 test1
-rw-rw-r-- 1 aaron aaron 4096020 May 13 11:52 test2

[email protected]:~/Documents/TLPI$ du -k test*
8 test1
4004 test2

可以看出两个文件的占有磁盘的大小是一样的,都是占有了4000M+20B,但是从真正的大小上面看,一个有8B,另外的是4004B。

好像是不对,应该是4008,原因是空洞边界的数据正好落在的快内。

外附上一段书上代码,寻找位置读写。

#include"tlpi_hdr.h"
#include<sys/stat.h>
#include<fcntl.h>
#include<ctype.h>

int
main(int argc,char *argv[])
{
    size_t len;
    off_t offset;
    int fd, ap, j;
    char *buf;
    ssize_t numRead, numWritten;

    if(argc < 3 || strcmp(argv[1],"--help") == 0)
        usageErr("%s file {r<length>|R<length>|w<string>|s<offset>}...\n",argv[0]);

    /*open file in read and write\ wr-wr-wr*/
    fd = open(argv[1],O_RDWR | O_CREAT, S_IRUSR | S_IWUSR |
                                        S_IRGRP | S_IWGRP |
                                        S_IWOTH | S_IWOTH);
    if(fd == -1)
        errExit("open");

    for(ap = 2; ap < argc; ap++)
    {
        switch(argv[ap][0])
        {
            case ‘r‘:/*display bytes at current offset as text*/
            case ‘R‘:/*display bytes at current offset as hex*/
                len = getLong(&argv[ap][1],GN_ANY_BASE, argv[ap]);
                buf = malloc(len);
                if(buf =NULL)
                    errExit("malloc");

                numRead = read(fd, buf, len);
                if(numRead == -1)
                    errExit("read");
                if(numRead == 0)
                    printf("%s:end-of-file\n",argv[ap]);
                else
                {
                    printf("%s: ",argv[ap]);
                    for(j = 0; j < numRead ; j++)
                    {
                        if(argv[ap][0] == ‘r‘)
                            printf("%c", isprint((unsigned char)buf[j]?buf[j]:‘?‘));
                        else
                            printf("%02x",(unsigned int)buf[j]);
                    }
                }
            free(buf);
            break;

            case ‘w‘ : /*write*/
                numWritten = write(fd, &argv[ap][1], strlen(&argv[ap][1]));
                if(numWritten == -1)
                    errExit("write");
                printf("%s wrote %ld bytes \n",argv[ap],(long)numWritten);
                break;

            case ‘s‘:/*change file offset*/
                offset = getLong(&argv[ap][1],GN_ANY_BASE, argv[ap]);
                if(lseek(fd, offset, SEEK_SET) == -1)
                {
                    errExit("lseek");
                }
                printf("%s: seek succeeded\n",argv[ap]);
                break;

            default:
                cmdLineErr("Argument must start with [rRsw]:%s\n",argv[ap]);
        }
    }
    exit(EXIT_SUCCESS);
}

  getLong()函数是自己的定义的,在之前就有描述。

file {r<length>|R<length>|w<string>|s<offset>}(具体用法)通过argv参数数组,提取数组第一字符作为选项,执行改选项需要的程序。
时间: 05-14

TLPI(liunx/unix系统编程手册)笔记(三) 文件IO:通用的IO模型的相关文章

TLPI(liunx/unix系统编程手册)笔记(四) 深入探究文件I/O

本章的重点我想就是原子操作,避免在几个进程在打开同一文件的时候造成的错误,了解一下时间片的概念会对本章有所帮助. (1)独占方式打开文件.(open     <-O_CREAT) 知道,open,可以创建文件并返回fd.当我们的进程运行到open这个函数时间片到了,另一个进程也对这个路径的文件open,那么时间片结束后两个进程都会认为自己是这个文件的拥有者.并未是独占创建打开的.在open 函数的第二个参数中有 O_EXCL 这种打开方式,可以解决独占的问题.另外可以在多进程对一个文件写的时候,

TLPI(liunx/unix系统编程手册)初读笔记

当然我只是记录一下我初读这本书的想法和我自己不懂该记下的地方,其他的地方就不一一论述,全部记下来就没有意思了. 若有什么错误,望大家指出,谢谢~希望有评论~ ------------------------------------------------------------------ 前言就是明确的介绍书的目的编程标准等等..source code在http://man7.org/大家可以去参阅 一章介绍POSIX标准和一些历史发展. 二章开始介绍基本概念: 讲到了内核的功能:1.提供了文

《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)

<Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h>文件中的常量. 通过cat 命令查看: [email protected]:~/Code/tlpi$ cat /usr/include/limits.h /* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005 Free Software

《Linux/Unix系统编程手册》读书笔记8 (文件I/O缓冲)

<Linux/Unix系统编程手册>读书笔记 目录 第13章 这章主要将了关于文件I/O的缓冲. 系统I/O调用(即内核)和C语言标准库I/O函数(即stdio函数)在对磁盘进行操作的时候都会发生缓冲.通过缓冲可以在一定程度上将用户空间与实际的物理设备分离,还可以减少内核访问磁盘的次数. 先来看看关于内核缓冲区高速缓冲:read和write调用在对磁盘文件进行操作的时候不会直接访问磁盘,如下图所示. 例如:write(fd, "abc", 3) write调用会将"

《Linux/Unix系统编程手册》读书笔记9(文件属性)

<Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有更深入的研究一定会写出来. 下图为磁盘分区与文件系统的关系 文件系统中的文件(目录)在i-node表上都有唯一的记录(i-node).i-node通过数据块指针指向数据块,这些数据块就是该i-node对应的文件的数据. i-node与数据块的关系如下: 因为Linux支持很多类型的文件系统,但是每种文件系统的

Linux/Unix系统编程手册--SOCKET章节读书笔记

SOCKET章节读书笔记 强烈推荐Linux/Unix系统编程手册,号称超越APUE的神书. backlog含义 #include <sys/socket.h> int listen(int socketfd, int backlog) backlog参数限制未决连接(未accept)的数量,在这个数量之内,connect会立刻成功. Linux上上限为128,定义在 udp已连接socket udp socket也是可以调用connect()的,这种叫已连接socket,内核会记录这个soc

Linux/UNIX系统编程手册 PDF下载

网盘下载地址:Linux/UNIX系统编程手册 PDF下载 – 易分享电子书PDF资源网 作者: Michael Kerrisk 出版社: 人民邮电出版社 原作名: The Linux Programming Interface: A Linux and UNIX System Programming Handbook 译者: 孙剑 许从年 董健 / 孙余强 郭光伟 陈舸 出版年: 2014-1 页数: 1176 定价: 158 装帧: 平装 内容简介 · · · · · · <linux/un

Linux/UNIX系统编程手册 练习3.8

闲来无聊看了看  3-1. 使用Linux专有的reboot系统调用重启系统时,必须将第二个参数magic2定义为一组magic号(例如:LINNUX_REBOOT_MAGIC2).这些号有何意义?(将magic号转换为十六进制数,对解题会有所帮助.) 刚看的时候 有点晕就去查了查 转换成16进制了 . 结果发现 是彩蛋.... 原文地址:https://www.cnblogs.com/jingchu/p/10262241.html

linux/unix系统编程手册源码编译

我的操作,我在官网下载 书本源代码 ,在windows 解压后 ftp工具 传到 linux虚拟机 然后 make 发现 报错 如: No rule to make target `../libtlpi.a', needed by 郁闷好久! 方案: 把源代码压缩包 ftp到虚拟机 在解压缩,make 就成功了! 注意,习惯: 永远在linux解压缩