标准C库的IO函数


前言

标准C库的IO函数就是调用Linux系统的IO函数。


一、标准C的IO函数

库函数参数返回值
FILE* fopen(const char* pathname,const char* mode)pathname: 路径名字,mode: 打开方式成功:文件指针,失败:NULL
int fclose(FILE* stream)stream: 文件指针成功:0,失败:-1
int fseek(FILE* stream,long offset,int whence)【文件偏移】stream: 文件指针,offset: 偏移数(负号向左,正好向右),whence: SEEK_SET文件的开头,SEEK_CUR 文件指针的当前位置,SEEK_END 文件的末尾成功:0,失败 -1
long int ftell(FILE *stream)【返回当前文件位置】stream: 文件指针成功:标识符的当前值,失败:-1
void rewind(FILE* stream) 【返回到文件开头】stream: 文件指针
char *fgets(char *s, int size, FILE *stream)s: 存储读到的字符,size: 最大存储字符数,stream: 文件指针成功:读到的字符,失败:NULL
int fputs(char* s,FILE* stream)s: 写入的字符,stream: 文件指针成功:0,失败:-1
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 【二进制读入】ptr: 存放文件内容地址,size: 读取的块大小,nmemb: 块数(读取文件大小 = 块数*每块大小) ,stream: 文件指针成功读取到文件块数
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) 【二进制写出】ptr: 写入文件内容地址,size: 块大小,nmemb: 块数(写出文件大小 = 块数*每块大小),stream 文件指针成功:写入到文件块数
int fflush(FILE *stream) 【刷新缓冲区】stream: 文件指针成功:0,失败:-1

文件指针(结构体)的包含内容:

  1. 文件描述符,本质是一个索引指向磁盘文件
  2. 文件读写指针位置,读写文件过程中指针的实际位置
  3. I/O缓冲区(内存地址),通过寻址找到对应的内存块,默认缓冲区为 8KB

从缓冲区把内容写到磁盘的操作:

  1. 刷新缓冲区 fflush
  2. 缓冲区已满
  3. 关闭文件,fclosereturn(main函数)exit(main函数)

网络编程需要使用Linux内核的I/O函数,否则用户会一直等待,直到刷新缓冲区

二、虚拟地址空间

当系统启动一个程序时,就会创建一个进程,该进程执行启动的程序,进程同时对应一个虚拟地址空间,为进程所拥有的资源。虚拟地址空间在32位机器中大小位2的32次方,64位机器中大小为2的48次方,其结构图如下图所示,虚拟地址空间会被CPU中的MMU(内存管理单元)映射到真实的物理地址,在真实的物理空间中不会有4GB大小。
参加这篇文章:虚拟地址空间图解在这里插入图片描述

三、文件描述符

程序只是一个文件,占用磁盘空间,进程可以理解成 操作系统为一个正在运行的程序分配资源的基本单位,进程拥有一个虚拟地址空间,其中文件描述符位于进程的虚拟地址空间的内核区,具体存在于进程控制块(一个复杂的结构体,叫做PCB)的文件描述符表中,PCB位于内核的内存管理模块,文件描述符表是一个默认大小为1024的数组。Linux系统中一切皆文件,所以把一切硬件驱动都看为文件,同一个文件可以被打开多次,且文件描述符不一样。
在这里插入图片描述

四、Linux的系统调用

open,打开文件

int open(const char* pathname,int flags),打开一个已经存在的文件,需要包含的头文件有三个:

  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  • 参数:
    pathname:要打开的文件路径
    flags:对文件的操作权限设置还有其他的设置, O_RDONLY, O_WRONLY, O_RDWR,这三个操作权限设置是互斥的
  • 返回值:返回一个新的文件描述符,如果调用失败,返回-1并设置errno

close

  • int close(int fd),关闭一个文件描述符,并且该文件描述符可以被重用。其头文件位于;
#include <unistd.h>
  • 参数
    fd:文件描述符;
  • 返回值:成功返回 0,如果调用失败,返回 -1 并设置errno

open,创建文件

  • int open(const char *pathname, int flags, mode_t mode),创建一个新文件,其头文件位于:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

参数:

  • pathname:要创建的文件的路径
  • flags:对文件的操作权限和其他的设置
    必选项:O_RDONLY, O_WRONLY, O_RDWR 这三个之间是互斥的
    可选项:O_CREAT 文件不存在,创建新文件;O_APPEND,在文件中追加内容,其他的权限这里不列出了;
    flags参数是一个int类型的数据,占4个字节,32位,每一位就是一个标志位。
  • mode:八进制的数,表示创建出的新的文件的操作权限,最终的权限是:mode & ~umask,umask的作用就是抹去某些权限。

返回值:返回一个新的文件描述符,如果调用失败,返回-1并设置errno

read

  • ssize_t read(int fd, void *buf, size_t count),从磁盘读文件数据到内存。其头文件位于;
#include <unistd.h>
  • 参数:
    - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
    - buf:需要读取数据存放的地方,数组的地址(传出参数)
    - count:指定的数组的大小,sizeof(buf)
  • 返回值:
    - 成功:
    >0: 返回实际的读取到的字节数
    =0:文件已经读取完了
    - 失败:-1 ,并且设置errno

write

  • ssize_t write(int fd, const void *buf, size_t count),从内存写数据到磁盘文件。其头文件位于;
#include <unistd.h>
    参数:
        - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
        - buf:要往磁盘写入的数据
        - count:要写的数据的实际的大小,buf中的有效数据,buf可能没有存满
    返回值:
        成功:实际写入的字节数
        失败:返回-1,并设置errno

lseek

  • off_t lseek(int fd, off_t offset, int whence);。其头文件位于;
    #include <sys/types.h>
    #include <unistd.h>

参数:

  • fd:文件描述符,通过open得到的,通过这个fd操作某个文件
  • offset:偏移量
  • whence:
    SEEK_SET 设置文件指针的偏移量
    SEEK_CUR 设置偏移量:当前位置 + 第二个参数offset的值
    SEEK_END 设置偏移量:文件大小 + 第二个参数offset的值

返回值:返回文件指针的位置

作用:
    1.移动文件指针到文件头
        lseek(fd, 0, SEEK_SET);

    2.获取当前文件指针的位置
    	lseek(fd, 0, SEEK_CUR);

    3.获取文件长度
    	lseek(fd, 0, SEEK_END);

    4.拓展文件的长度,当前文件10b, 110b, 增加了100个字节
   		lseek(fd, 100, SEEK_END)
    注意:需要写一次数据

stat

int stat(const char *pathname, struct stat *statbuf),作用是获取一个文件相关的一些信息,其头文件位于:

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

参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量(下面代码所示),传出参数,用于保存获取到的文件的信息

返回值:

  • 成功:返回0
  • 失败:返回-1 设置errno
struct stat {
	dev_t st_dev; // 文件的设备编号
	ino_t st_ino; // 节点
	mode_t st_mode; // 文件的类型和存取的权限
	nlink_t st_nlink; // 连到该文件的硬连接数目
	uid_t st_uid; // 用户ID
	gid_t st_gid; // 组ID
	dev_t st_rdev; // 设备文件的设备编号
	off_t st_size; // 文件字节数(文件大小)
	blksize_t st_blksize; // 块大小
	blkcnt_t st_blocks; // 块数
	time_t st_atime; // 最后一次访问时间
	time_t st_mtime; // 最后一次修改时间
	time_t st_ctime; // 最后一次改变时间(指属性)
};

st_mode 变量的表示方式
st_mode 与掩码进行按位与,可以得到文件类型,同理获得文件的操作权限。
在这里插入图片描述

lstat

int stat(const char *pathname, struct stat *statbuf),获取软链接的信息,头文件位于:

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

参数:

  • pathname:操作的文件的路径
  • statbuf:结构体变量,传出参数,用于保存获取到的文件的信息

返回值:

  • 成功:返回0
  • 失败:返回-1 设置errno

access

int access(const char *pathname, int mode),作用为:判断某个文件是否有某个权限,或者判断文件是否存在。头文件#include <unistd.h>

参数:

  • pathname: 判断的文件路径
  • mode:
    R_OK: 判断是否有读权限
    W_OK: 判断是否有写权限
    X_OK: 判断是否有执行权限
    F_OK: 判断文件是否存在

返回值:成功返回0, 失败返回-1

chmod

int chmod(const char *pathname, mode_t mode),修改文件的权限。头文件#include <sys/stat.h>

参数:

  • pathname: 需要修改的文件的路径
  • mode:需要修改的权限值,八进制的数

返回值:成功返回0,失败返回-1

chmod

int chmod(const char *pathname, uid_t owner, gid_t group),修改文件的所有者或者所在组

参数:

  • pathname: 需要修改的文件的路径
  • owner:文件所有者的id
  • group:文件所在组的id

返回值:成功返回0,失败返回-1

truncate

int truncate(const char *path, off_t length),缩减或者扩展文件的尺寸至指定的大小。

参数:

  • path: 需要修改的文件的路径
  • length: 需要最终文件变成的大小

返回值: 成功返回0, 失败返回-1

mkdir

int mkdir(const char *pathname, mode_t mode),创建一个目录,头文件

    #include <sys/stat.h>
    #include <sys/types.h>
    参数:
        pathname: 创建的目录的路径
        mode: 权限,八进制的数
    返回值:
        成功返回0, 失败返回-1

rmdir

int rmdir(const char *pathname),只能删除空目录。头文件

    #include <sys/stat.h>
    #include <sys/types.h>
    参数:
        pathname: =目录的路径
    返回值:
        成功返回0, 失败返回-1

rename

int rename(const char *oldpath, const char *newpath),重命名。头文件#include <stdio.h>

参数:

  • oldpath:旧的名字,
  • newpath:新的名字

返回值:

  • 成功返回0, 失败返回-1

chdir

int chdir(const char *path), 修改进程的工作目录,比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder。头文件 #include <unistd.h>

参数:
    path : 需要修改的工作目录

getcwd

char *getcwd(char *buf, size_t size),获取当前工作目录,头文件 #include <unistd.h>

作用:
参数:
    - buf : 存储的路径,指向的是一个数组(传出参数)
    - size: 数组的大小
返回值:
    返回的指向的一块内存,这个数据就是第一个参数

opendir

DIR *opendir(const char *name),打开一个目录,头文件

#include <sys/types.h>
#include <dirent.h>
参数:
    - name: 需要打开的目录的名称
返回值:
    DIR * 类型,理解为目录流
    错误返回NULL

readdir

struct dirent *readdir(DIR *dirp),读取目录中的数据,头文件#include <dirent.h>

- 参数:dirp是opendir返回的结果
- 返回值:
    struct dirent,代表读取到的文件的信息
    读取到了末尾或者失败了,返回NULL
struct dirent{
	// 此目录进入点的inode
	ino_t d_ino; 
	// 目录文件开头至此目录进入点的位移
	off_t d_off; 
	// d_name 的长度, 不包含NULL字符
	unsigned short int d_reclen; 
	// d_name 所指的文件类型
	unsigned char d_type; 
	// 文件名
	char d_name[256];
};

变量 d_type:

DT_BLK - 块设备 
DT_CHR - 字符设备 
DT_DIR - 目录 
T_LNK - 软连接 
DT_FIFO - 管道
DT_REG - 普通文件
DT_SOCK - 套接字
DT_UNKNOWN - 未知

closedir

int closedir(DIR *dirp),,关闭目录,头文件

#include <sys/types.h>
#include <dirent.h>
参数:
    - dirp: 目录的名称
返回值:
	成功返回0, 失败返回-1

dup

int dup(int oldfd),复制一个新的文件描述符, 从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符,头文件 #include <unistd.h>

    参数: oldfd:旧的文件描述符
    返回值:复制的文件描述符,失败返回-1,设置errno
    
    fd=3, int fd1 = dup(fd),
    fd指向的是a.txt, fd1也是指向a.txt

dup2

int dup2(int oldfd, int newfd),作用:重定向文件描述符,头文件 #include <unistd.h>

    oldfd 指向 a.txt, newfd 指向 b.txt
    调用函数成功后:newfd 和 b.txt 取消关联, newfd 指向了 a.txt
    oldfd 必须是一个有效的文件描述符
    oldfd和newfd值相同,相当于什么都没有做
    
    参数:
    	oldfd:文件描述符     newfd:文件描述符 
    返回值:成功返回 newfd (文件描述符),失败返回-1

fcntl

int fcntl(int fd, int cmd, … /* arg */ ),作用:复制文件描述符 和 设置/获取文件的状态标志,头文件

#include <unistd.h>
#include <fcntl.h>
参数:
 fd : 表示需要操作的文件描述符
 cmd: 表示对文件描述符进行如何操作
    F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
     int ret = fcntl(fd, F_DUPFD);

    F_GETFL : 获取指定的文件描述符文件状态flag
     	获取的flag和我们通过open函数传递的flag是一个东西。

    F_SETFL : 设置文件描述符文件状态flag
     	必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
     	可选性:O_APPEND, NONBLOCK
    	O_APPEND 表示追加数据
    	NONBLOK 设置成非阻塞
  
  阻塞和非阻塞:描述的是函数调用的行为。

errno

Liunx系统调用发生错误时,会记录错误信息到errno中, errno:属于Linux系统函数库,库里面的一个全局变量,记录的是最近的错误号。

#include <stdio.h> //perror的库
void perror(const char *s);
//作用:打印errno对应的错误描述
//s参数:用户描述,比如hello,最终输出的内容是  hello:xxx(xxx为实际的错误描述)

总结

牛客网C++课程,记录学习过程。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值