Linux 学习记录22(IO篇)

Linux 学习记录22(IO篇)

在这里插入图片描述

本文目录

  • Linux 学习记录22(IO篇)
  • 一、关于光标位置相关的函数 (fseek、ftell、rewind)
    • 1. fseek
    • 2. ftell
    • 3. rewind
  • 二、文件IO
    • `需要使用的库`
    • 1. 文件描述符
    • 2. open函数的使用
    • 3. umask
    • 4. close的使用
    • 5. read函数的使用
    • 6. write函数的使用
    • 7. 文件IO中的lseek函数
  • 三、文件描述符拷贝问题
    • 1. 文件描述符的直接拷贝
    • 2. 文件描述符拷贝之dup函数
    • 3. 使用open多次打开同一个文件
    • 4. 文件描述符拷贝函数之dup2函数
    • 通过文件描述符获取文件名
  • 思维导图
  • 练习
    • 1. 使用read、write实现两个文件的拷贝

一、关于光标位置相关的函数 (fseek、ftell、rewind)

1. fseek

函数原型:int fseek(FILE *stream, long offset, int whence);
功能:修改文件光标位置
参数1:要修改光标的文件
参数2:偏移量
	>0:表示向后偏移
	=0:不偏移
	<0:表示向前偏移
参数3:偏移的起始位置
	SEEK_SET:文件的开头
	SEEK_CUR:当前位置
	SEEK END:文件结尾
返回值:成功返回,失败返回-1并置位错误码
=============================================================
int main(int argc, char const *argv[])
{ 
    FILE* fp1 = NULL;
    if((fp1=fopen("./file01.txt","w+")) == NULL)
    {//打开文件写数据
        perror("open file");
        return -1;
    }
    fprintf(fp1,"1: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"2: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"3: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"4: hello word\r\n");//写入一行,光标向后偏移
    fseek(fp1,0,SEEK_SET);//光标定位到文件开头,不偏移
    fgets(str1,sizeof(str1),fp1);
    fclose(fp1);
    printf("%s\r\n",str1);
    return 0;
}

2. ftell

以'a'或'a+'的形式打开的文件不能更改光标位置
但是以'a+'的形式打开的文件能够修改读光标

函数原型:long ftel(FILE *stream);
功能:获取光标当前位置
参数1:文件指针
返回值:返回光标所在位置
============================================
int main(int argc, char const *argv[])
{ 
    FILE* fp1 = NULL;
    if((fp1=fopen("./file01.txt","w+")) == NULL)
    {//打开文件写数据
        perror("open file");
        return -1;
    }
    fprintf(fp1,"1: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"2: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"3: hello word\r\n");//写入一行,光标向后偏移
    fprintf(fp1,"4: hello word\r\n");//写入一行,光标向后偏移
    printf("当前光标位置为:%ld\r\n",ftell(fp1));
    fclose(fp1);
    printf("%s\r\n",str1);
    return 0;
}

3. rewind

函数原型:void rewind(FILE *stream);
功能:将文件指针回到文件的开头。
参数1:指定文件指针
返回值:无返回值

二、文件IO

需要使用的库

#include 
#include 
#include 
#include 
文件IO:基于系统调用得方式,只要调用文件IO得接口,程序就会从用户空间向内核空间进行一次交互
效率相较于标准IO较低,因为没有缓冲区

文件IO的接口

open、read、write、close、Iseek…

1. 文件描述符

文件描述符:

  1. 文件描述符是一个大于等于0的非负整数,使用open打开一个文件后,就会返回该文件的描述符,在之后想要操作文件,只需通过该文件描述符即可
  2. 在一个正在执行的程序中,默认打开了三个文件描述符0(stdin)、1(stdout)、2(stderr)
  3. 文件描述符的使用原则: 最小末分配原则
  4. 一个程序中的文件描述符的最大承载量默认为1024
int main(int argc, char const *argv[])
{ 
    printf("fileno of stdin = %d\n", stdin->_fileno);
    printf("fileno of stdout = %d\n", stdout->_fileno);
    printf("fileno of stderr = %d\n", stderr->_fileno);
    return 0;
}
输出>>
fileno of stdin = 0
fileno of stdout = 1
fileno of stderr = 2

2. open函数的使用

int open(const char *pathname, int flags);//无需创建文件
int open(const char *pathname, int flags, mode t mode);//需要创建文件
功能:打开一个文件
参数1: 文件路径,跟fopen的第一个参数一致
参数2:打开方式
	1: O_RDONLY 只读 2: O_WRONLY 只写 3: O_RDWR 读写
	===============以上一个必须选择其中一个,下面的可以作为选加====================
	1. O_CREAT:如果文件不存在,创建一个文件,如果加了该选项,那么第三个参数也必须要加
	2. O_APPEND: 追加写
	3. O_TRUNC:如果文件存在,则清空内容
	4. O_EXCL: 判断文件是否已经存在,如果已经存在了,则open函数会置位错误码为: EEXIST,跟0 CREAT
	5. 使用例子"w+"-> O_RDWR|O_CREAT|O_TRUNC
参数3: 掩码 文件权限,创建文件时的权限
	目录的最大权限:0777
	普通文件的最大权限是:0666
	最终的权限是给定的(mode & rumask)
	umask:是系统给定的黑认的掩码
	更改掩码的指令:umask 数字
返回值:成功返回打开文件的文件描述符,失败返回-1
=========================================================================================
int main(int argc, char const *argv[])
{
    int fb = 0;
    if((fb=open("01open.txt",O_RDWR|O_CREAT|O_TRUNC,0777) == -1))
    {//文件打开失败
        perror("open file: ");
        return 1;
    }

    close(fb);//关闭文件
    return 0;
}
=========================================================================================
int main(int argc, char const *argv[])
{
    int fb = 0;
    if((fb=open("02open.txt",O_RDWR|O_CREAT|O_EXCL) == -1))
    {//文件打开失败
        if(errno == EEXIST)
        {
            printf("文件已存在,无需重新创建\r\n");
            fb = open("02open.txt",Rp);
        }else
        {
            perror("open file");return -1;
        }
        return 1;
    }

    close(fb);//
    return 0;
}

掩码的相关表格
Linux 学习记录22(IO篇)_第1张图片

使用宏:

#define R O_RDONLY
#define W O_WRONLY|O_CREAT|O_TRUNC
#define A O_WRONLY|O_CREAT|O_ACCMODE
#define Rp O_RDWR
#define Wp O_RDWR|O_CREAT|O_TRUNC
#define Ap O_RDWR|O_CREAT|O_TRUNC

3. umask

umask是创建文件时的掩码,默认为0002,对其他用户没有写功能
查看umask
在这里插入图片描述
修改umask
在这里插入图片描述

4. close的使用

头文件:
#include 
函数原型:int close(int fd);
功能:关闭一个文件参数:要关闭文件的文件描述符
返回值: 成功返回e,失败返回-1并置位错误码
===========================================
close(1);

5. read函数的使用

函数原型:ssize_t read(int fd, void *buf, size_t count);
功能:从给定文件中读取从count个数据到buf中
参数1:被读取文件
参数2:读取后的数据容器,是一个万能指针,可以读取任意类型的数据
参数3:读取的数量
返回值:返回值>0读取的个数,返回值=0文件读取结束,失败返回-1并置位错误码

6. write函数的使用

函数原型:ssize_t write(int fd, const void *buf, size_t count);
功能:向给定文件中写入buf中的count个数据到fdq中
参数1:被写文件
参数2:读取后的数据容器,是一个万能指针,可以读取任意类型的数据
参数3:读取的数量
返回值:返回值>0读取的个数,返回值=0文件读取结束,失败返回-1并置位错误码

7. 文件IO中的lseek函数

函数原型:off_t lseek(int fd, off_t offset, int whence);
功能:移动光标位置
参数1:文件描述符
参数2:偏移量
参数3:偏移的起始位置
	1. SEEK_SET:文件开头
	2. SEEK_CUR:当前位置
	3. SEEK_END:文件末尾
返回值:失败返回-1,并置位错误码,超过返回光标当前位置到文件开头的偏移量                                                                                                                                                                                                                       

三、文件描述符拷贝问题

1. 文件描述符的直接拷贝

使用变量拷贝文件描述符,其实只是拷贝变量的值,并没有产生新的文件描述符,只是在程序中多了一个变量,记录该文件描述符而已,所以无论操作哪个变量,都是对该文件描述符的操作,使用的是同一个光标

#include

int main(int argc, const char *argv[])
{
    int fd1;
    //以只读的形式打开一个文件
    if((fd1 = open("./open.txt", O_RDONLY)) == -1)
    {
        perror("open file");
        return -1;
    }
    //定义容器
    char buf[10] = "";
    int ret = read(fd1, buf, sizeof(buf));
    write(1, buf, ret);            //向终端打印数据
    printf("\n");
    int fd2 = fd1;         //将文件描述符直接拷贝
    printf("fd1 = %d, fd2 = %d\n", fd1, fd2);
    char buf1[10];
    ret = read(fd2, buf1, sizeof(buf1));
    write(1, buf1, ret);//如果终端上输出的跟fd1输出结果一致
                        //说明两个文件使用的是不同光标
                        //如果不一致,说明两个文件使用的是同一光标
    return 0;
}

2. 文件描述符拷贝之dup函数

文件原型:int dup(int oldfd);
功能:通过给定的旧文件描述符,拷贝出一个新文件描述符
参数:旧文件描述符
返回值:成功返回:新文件描述符,使用最小未使用原则
	失败返回-1并置位错误码
===================================================================
int main(int argc, char const *argv[])
{
    int fd1 = 0;
    int fd2 = 0;
    int ret = 0;
    char str[5] = {0};
    if((fd1 = open("./file01.txt",R)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }
    fd2 = dup(fd1);//拷贝出一个新的文件描述符,其大小为最小的未使用的描述符
    printf("fd1 = %d fd2: %d \r\n",fd1,fd2);
    close(fd1);
    close(fd2);
    return 0;
}
输出>>
fd1 = 3 fd2: 4

3. 使用open多次打开同一个文件

两个文件描述符不共享光标

int main(int argc, char const *argv[])
{
    int fd1 = 0;
    int fd2 = 0;
    int ret = 0;
    char str[5] = {0};
    
    if((fd1 = open("./file01.txt",R)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }
    if((fd2 = open("./file01.txt",R)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }

    printf("fd1 = %d fd2: %d \r\n",fd1,fd2);

    close(fd1);
    close(fd2);

    return 0;
}
输出>>
fd1 = 3 fd2: 4 

4. 文件描述符拷贝函数之dup2函数

函数原型:int dup2(int oldfd, int newfd);
函数功能:它将文件描述符oldfd复制到文件描述符newfd上,如果newfd已经打开,则先将其关闭。
		dup2返回的是复制后的文件描述符newfd
参数1:旧的文件描述符
参数2:新的文件描述符
返回值:如果出现错误则返回-1=======================================================================
dup2(fd, STDIN_FILENO); // 将fd重定向到标准输入
dup2(fd, STDOUT_FILENO); // 将fd重定向到标准输出
dup2(fd, STDERR_FILENO); // 将fd重定向到标准错误

通过文件描述符获取文件名

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int fd1 = 0;
    int fd2 = 0;
    int ret = 0;
    char str[50] = {0};
    char file_path[100] = {0};
    
    if((fd1 = open("./file01.txt",R)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }
    
    snprintf(str,sizeof(str), "/proc/self/fd/%d", fd1);
    readlink(str,file_path,sizeof(file_path)-1);

    printf("%s\n",file_path);

    close(fd1);
    close(fd2);

    return 0;
}
输出>>
/home/ubuntu/Desktop/learn/IO/5_26/file01.txt

思维导图

Linux 学习记录22(IO篇)_第2张图片

练习

1. 使用read、write实现两个文件的拷贝

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define R O_RDONLY
#define W O_WRONLY|O_CREAT|O_TRUNC
#define A O_WRONLY|O_CREAT|O_ACCMODE
#define Rp O_RDWR
#define Wp O_RDWR|O_CREAT|O_TRUNC
#define Ap O_RDWR|O_CREAT|O_TRUNC

int main(int argc, char const *argv[])
{
    int fd1 = 0;
    int fd2 = 0;
    int ret = 0;
    int cnt = 0;
    char str[5] = {0};
    if((fd1 = open("./file01.txt",R)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }
    if((fd2 = open("./file02.txt",W,0666)) == -1)
    {//文件打开失败
        perror("open file");
        return -1;
    }
    do
    {
        ret = read(fd1,str,sizeof(str));
        cnt+=ret;
        write(fd2,str,ret);
    }while(ret);

    printf("文件大小: %d\n",cnt);

    close(fd1);
    close(fd2);
    return 0;
}

你可能感兴趣的:(Linux学习记录,linux,学习,运维)