Linux文件

目录

1 C库IO函数工作流程

2 Linux文件I/O

2.1 大文件写入另一个文件

2.1.1 perror和errno

2.2 阻塞读和非阻塞读

2.2.1 阻塞读终端

2.2.2 非阻塞读终端

2.3 stat函数

2.3.1 stat命令

2.3.2 stat函数

2.4 文件属性相关的函数

2.5 dup和dup2——重定向


1 C库IO函数工作流程

Linux文件_第1张图片

fflush,刷新缓冲区,输入则丢弃;输出,则写入到输出设备(磁盘或屏幕)

2 Linux文件I/O

1、进程控制块PCB标识唯一进程

2、PCB块中有一个数组——文件描述符表,索引0~1023个文件描述符。每打开文件就占用一个描述符,且占用的时空闲的而且最小的文件描述符。

3、前三个分别为——标准输入文件(STDIN_FILENO),标准输出文件(STDOUT_FILENO),错误文件(STDERR_FILENO)。这三个默认是打开的。

4、通过文件描述符找到磁盘文件

Linux文件I/O

1、open

返回值为文件描述符

(1)int open(const char * pathname, int flags);

(2)int open(const char * pathname, int flags, mode_t mode);

flags——O_RDONLY,O_WRONLY,O_RDWR(必选项);O_CREAT(创建文件),O_APPEND(追加文件),O_TRUNC(文件截断),O_NONBLOCK(设置非阻塞)。flags的每一个位对应不同的操作

mode_t——访问权限。8进制数

2、read

ssize_t read(int fd, void * buf, size_t count);  //count表示能存放的最大字节数

fd——文件描述符

成功,>0,返回读出的字节数,=0,文件读完;失败,返回-1。

3、write

ssize_t write(int fd, const void * buf, size_t count);  //count,表示buf中字节总数

失败,返回-1;成功,返回写入到文件的字节数

4、lseek

off_t lseek(int fd, off_t offset, int whence);  //返回指针距离文件首部的距离

whence:SEEK_SET、SEEK_CUR、SEEK_END

offset:相对于whence来说

(1)文件指针移动到头部

lseek(fd, 0, SEEK_SET);  //offset是相对于whence来说的

(2)获取文件指针当前位置

int len = lseek(fd, 0, SEEK_CUR);

(3)获取文件长度

int len = lseek(fd, 0, SEEK_END)

(4)文件扩展

在SEEK_END,进行offset > 0的lseek调用,然后写入一些字符,即可扩展文件的size成功。

扩展的作用——使用扩展,用占位符占用一部分空间先占用,当使用时填充。当多线程写时,也需要现有一块空间,然后不同的线程操作一块空间中的不同部分。

系统函数的read和write直接操纵磁盘,没有I/O缓冲区

2.1 大文件写入另一个文件

Linux文件_第2张图片

首先读取文件到缓冲区,然后把缓冲区的文件写入另一个文件

这里是write使用了len而不是strlen(buf),因为buf中存放的并不是字符串,而是一个个字符,即buf并不是以'\0'结尾的标准字符串。而strlen的计算是根据'\0'出现的位置计算的。

2.1.1 perror和errno

errno是系统函数库的全局变量——当open,read,write,lseek等调用失败时,会设置errno的值,系统根据这个值,提示错误信息

perror()函数调用时,会读取errno的值,然后根据值来提示错误信息

man perror

#include 

void perror(const char *s);

#include 
const char * const sys_errlist[];
int sys_nerr;
int error;

 

2.2 阻塞读和非阻塞读

终端设备默认阻塞,管道默认是阻塞的套接字默认也是阻塞

阻塞和非阻塞是文件的属性。——O_NONBLOCK

2.2.1 阻塞读终端

对于标准输入,它就是阻塞的,等待客户输入完成

Linux文件_第3张图片

这的STDIN_FILENO,是标准输入终端描述符;STDOUT_FILENO,是标准输出描述符

这里从标准输入read,其作用是和scanf一样;向标准输出write,其作用是和printf一样的。

最终生成file1.out可执行程序

执行file1.out结果分析

默认bash是前台程序,当调用file1.out启动一个程序时,bash变成了后台程序。此时的前台程序是file1.out。

当file1.out等待用户输入10个字符,并将输入的10个字符输出到终端后,bash从后台程序变成前台程序。而bash也是一直在等待客户输入命令(阻塞)后执行。此时缓冲区中还有字符fuck,所以bash读取缓冲区的字符(遇到回车时即认为输入完毕,而第一次输入时在最后输入了回车键)作为命令执行。

2.2.2 非阻塞读终端

当缓冲区没有数据时,调用sleep,让出CPU

2.3 stat函数

 

2.3.1 stat命令

stat filename  #查看文件属性

Linux文件_第4张图片

2.3.2 stat函数

man 2 stat

#include 
#include 
#include 

int stat(const char * pathname, struct stat *statbuf);

int fstat(int fd, struct stat *statbuf);

int lstat(const char * pathname, struct stat *statbuf);


#include 
#include 

int fstatat(int dirfd, const char * pathname, struct stat *statbuf, int flags);


struct stat {
    dev_t st_dev;  //文件的设备编号,ID of device containing file
    ino_t st_ino;  //节点
    mode_t st_mode;  //文件类型和存取权限
    nlink_t st_link;
    uid_t st_uid;
    gid_t st_gid;
    dev_t st_rdev;  //
    off_t st_sizt;  //文件字节数
    blksize_t st_blksize;  //块大小(文件系统的I/O缓冲区大小)
    blkcnt_t st_blocks;  //块数
    time_t st_atime;
    time_t st_mtime;
    time_t st_ctime;
};
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    struct stat sb;
    
    if (argc != 2){
        fprintf(stderr, "Usage: %s \n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (lstat(argv[1], &sb) == -1){
        perror("lstat");
        exit(EXIT_FAILURE);
    }
    
    printf("ID of containing device : [%lx, %lx]\n", (long)major(sb.st_dev), (long)minor(sb.st_dev));

    printf("File type:        ");
    
    switch (sb.st_mode & S_IFMT){  //S_IFMT,是为了过滤文件类型以外的属性
        case S_IFBLK: printf("block device\n"); break;
        case S_IFCHR: printf("character device\n"); break;
        case S_IFDIR: printf("directory\n"); break;
        case S_IFIFO: printf("FIFO/pipe\n"); break;
        case S_IFLNK: printf("symlink\n"); break;
        case S_IFREG: printf("regular file\n"); break;
        case S_IFSOCK: printf("socket\n"); break;
        default: printf("unknown?\n");
   }
    
    printf("I-node number: %ld\n", (long)sb.st_ino);

    return 0;
}

2.4 文件属性相关的函数

1、access——检测是否具备某种权限

int access(const char * pathname, int mode);  //检测当前用户对文件是否具备某种权限

mode——R_OK,W_OK,X_OK,F_OK

2、chmod——修改文件权限

int chmod(const char * filename, int mode);

3、truncate——扩展文件大小

int truncate(const char *path, off_t length);  //length为重新设置的空间,比原来大,则扩展;比原来小,则缩小

2.5 dup和dup2——重定向

1、dup——复制文件描述符

int dup(int oldfd);

返回值:新的文件描述符。

调用成功,有两个文件描述符指向同一个文件

2、dup2——复制文件描述符

int dup2(int oldfd, int newfd);  //文件描述符的重定向——把newfd定向到了oldfd所指文件

newfd已经指向了一个文件,首先close(newfd),然后调用dup2,而oldfd和newfd都指向了oldfd指向的文件。

 

 

 

 

 

 

你可能感兴趣的:(#,Linux)