Linux系统编程之文件I/O (一)

2021-11-29  本文已影响0人  iMikasa_

本文算是入门系统调用,以文件io为起点,研究系统调用的API,包括打开文件、关闭文件、从文件中读取数据和向文件中写数据,当然是对磁盘文件的I/O操作,本文只是作为起点,起点稍微低点有利于持续学习信心,坑以后埋。

文件描述符

如果想对一个文件进行读写操作,首先需要找到这个文件,那我们如何找到这个文件呢?这个文件描述符就可以找到所需要读写的文件。对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传送给read或write。

打开一个文件:open()

open()既能打开一个已经存在的文件,也能创建并打开一个新文件。

#include <fcntl.h>

// 打开一个已经存在的磁盘文件
int open(const char *pathname, int flags);
// 打开磁盘文件, 如果文件不存在, 就会自动创建
int open(const char *pathname, int flags, mode_t mode);

成功返回文件描述符,发生错误则返回-1

参数介绍

关闭一个文件:close()

通过 open 函数可以让内核给文件分配一个文件描述符,如果需要释放这个文件描述符就需要关闭文件。对应的这个系统函数叫做 close

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

创建一个新文件:creat()

使用creat()函数创建一个新文件,并以只写的方式打开;

#include <fcntl.h>
int creat(const char * pathname, mode_t mode)

pathname:要创建的文件名;
mode:要创建的新文件的权限;
调用成功返回1,失败返回-1;
等同于

//建议使用下面的代码创建新文件
open(pathname,O_CREATE | O_WRONLY | O_TRUNC , mode);

文件定位:lseek()

每一个打开的文件都有一个与其相关的文件偏移量,在系统默认的情况下,新打开的文件的偏移量为0,它通常是一个非负整数,用以度量从文件开始处计算的字节数。通常,读、写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
一些小应用

将偏移量移动到文件头部

lseek(fd,0,SEEK_SET);

获取当前文件偏移量

lseek(fd,0,SEEK_CUR);

获取文件的大小

lseek(fd,0,SEEK_END);
文件空洞

lseek仅将当前的文件偏移量记录在内核中,它并不引起任何I/O操
作。然后,该偏移量用于下一个读或写操作。
文件偏移量可以大于文件的当前长度,在这种情况下,对该文件的
下一次写将加长该文件,并在文件中构成一个空洞,这一点是允许的。
位于文件中但没有写过的字节都被读为0。
文件中的空洞并不要求在磁盘上占用存储区。具体处理方式与文件系统的实现有关,当定位到超出文件尾端之后写时,对于新写的数据需要分配磁盘块,但是对于原文件尾端和新开始写位置之间的部分则不需要分配磁盘块。


image.png

读取文件内容:read()

read 函数用于读取文件内部数据,在通过 open 打开文件的时候需要指定读权限

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

数据写入文件:write()

write 函数用于将数据写入到文件内部,在通过 open 打开文件的时候需要指定写权限

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
文件读写实现的文件拷贝(简单实现cp命令)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define MAX 1024

int main(int argc, char const *argv[]){
    char buf[MAX];
    int in,out;
    int num;
    if (argc != 3)
        exit(1);
    if ((in = open(argv[1],O_RDONLY)) == -1){
        perror("fail to open");
        exit(1);
    }
    if ((out = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT)) == -1){
        perror("fail to open");
        exit(1);
    }
    
    while ((num = read(in,buf,MAX)) > 0){
        if (write(out,buf,num)!=num){
            perror("fail to write");
            exit(1);
        }
    }
    if (num < 0){
        perror("fail to read");
        exit(1);
    }
    close(in);
    close(out);
    return 0;
}

使用

$ gcc my_cp.c -o my_cp
$ ./my_cp myfile.txt myfile1.txt        #myfile.txt是源文件,要被复制的文件 ;myfile1.txt 是目标文件,没有就会新建,有就覆盖

系统调用学习不仅仅是这些API的使用方法更多是一些Linux理论概念上的自我理解,深入学习.......

(待续)

参考

《UNIX环境高级编程》
《Linux/UNIX系统编程手册》
《Linux C程序设计 王者归来》
《Linux C 一站式学习》

上一篇 下一篇

猜你喜欢

热点阅读