学习笔记4

Linux文件IO操作

文件描述符

用一个非负整数来标识一个文件,这个非负的整数就是文件描述符。
打开一个文件,系统就会为我们分配一个文件描述符,操作文件描述符就等价于操作文件.

文件描述符表:进程运行的时候,系统创建文件描述符表来管理系统中文件描述符。
每一个进程默认打开了3个文件描述符(0标准输入设备/键盘 1标准输出设备/屏幕 2标准错误输出/屏幕)

文件的打开读写关闭

打开文件open

#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);//打开不存在的文件
//flags:read write操作文件的权限
//mode:该文件在磁盘中相对于用户的权限 
  • 功能:
    打开文件,如果文件不存在则可以选择创建。
  • 参数:
    pathname:文件的路径及文件名
    flags:打开文件的行为标志,必选项 O_RDONLY, O_WRONLY, O_RDWR
    mode:这个参数,只有在文件不存在时有效,指新建文件时指定文件的权限
  • 返回值:
    成功:成功返回打开的文件描述符
    失败:-1

关闭文件close

#include <unistd.h>
int close(int fd);
  • 功能:
    关闭已打开的文件
  • 参数:
    fd : 文件描述符,open()的返回值
  • 返回值:
    成功:0
    失败: -1, 并设置errno

文件的写操作write

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
  • 功能:
    把指定数目的数据写到文件(fd)
  • 参数:
    fd : 文件描述符
    buf : 数据首地址
    count : 写入数据的长度(字节)
  • 返回值:
    成功:实际写入数据的字节个数
    失败: - 1

read读取文件数据

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
  • 功能:
    把指定数目的数据读到内存(缓冲区)
  • 参数:
    fd : 文件描述符
    buf : 内存首地址
    count : 读取的字节个数
  • 返回值:
    成功:实际读取到的字节个数
    失败: - 1 文件末尾返回0

分区



假如上图是第一个硬盘,那么它的设备名为:

1:sda1 2:sda2 3:sda3 4:sda4 5:sda5 6:sda6

挂载

只有在windows中才有分配盘符这个说法,Linux里叫挂载

在给分区分配盘符的过程叫做挂载

分配完盘符,应该叫挂载点,即:

分配盘符挂载 盘符挂载点

在window中使用C/D/E/F作为盘符 而在Linux中使用空的目录名称作为盘符

理论上,任何一个目录都可以做为盘符,但还是有些不行,后面说

必须要作为分区的有:

根分区 swap分区(虚拟内存:当内存不够用时,从这部分拿一部分去当内存使用,理论上来讲,大小应该为内存的2倍,但是达到2g的时候,如果再给大,不会给系统带来任何作用,只会占用硬盘空间)

虚拟内存使用的是硬盘,速度跟硬盘是一样的,没有真正内存那么快

如果没有上面两个分区,则Linux无法安装

启动分区:任何操作系统要正常启动,就必须要有一定的空余空间

如果没给boot分区,所有数据都放在根分区下,如果根分区被放满,

则Linux就没法启动了,所以有必要设置出一个启动分区

Linux中,根分区是最高级,在根分区中保存一级目录,在一级目录中保存二级目录

在Windows中,C/D/E/F盘是并列的

但在Linux中,根分区可以单独分配一个磁盘空间

假设给根分区分配一个sda3,那么往根分区写入数据时数据都会放在sda3中

也可以给根分区的子目录指定独立的分区空间

可以理解为,分区不用并列在同一级目录里,可以纵向嵌套,也可以横向并列,而且空间单独计算.并不会因为嵌套了就占用更多空间

总结

格式化是为了写入文件系统

但在写入文件系统前,会清空磁盘

但会有人误以为格式化只是清空硬盘

挂载:给每个分区挂载一个挂载点,这个挂载点,只能是目录,而且目录要是空目录才可以

Linux系统调用文件操作

Linux的文件结构
对linux来说,一切设备都是文件,这是通过底层的设备驱动程序进行抽象的。文件除了自己所包含的内容外,还有一个名字和一些属性,如创建修改日期和它的访问权限等,这些属性被保存在文件的inode节点中,它是文件系统中一个特殊的数据块,还包含文件的长度和在磁盘上的存放位置等。OS使用的是文件的inode编号,目录结构为文件命名只是为了便于人们使用。
用stat命令可以查看文件的详细信息

  • 1.1 目录
    目录是用于保存其它文件的节点号和名字的文件,目录文件中的每个数据项都是指向某个文件节点的链接,删除文件名就等于删除与之对应的链接。删除一个文件时,实际上是删除了该文件对应的目录项,同时指向该文件的链接数减1,如果指向某个文件的链接数为0,则该节点及其指向的数据不再被使用,磁盘上相应的位置就被标记为可用空间。

  • 1.2 系统调用与库函数
    我们可以通过两种方式访问文件,一种是linux的操作系统接口,即系统调用,另一种是GNU在对系统调用进行封装优化处理后的标准输入输出函数<stdio.h>。
    针对输入输出操作直接使用底层系统调用时的效率很低,因为在执行系统调用函数时,Linux必须实现用户态和内核态之间的切换,这种开销是非常大的,库函数通过设置缓冲区每次读写大量数据而减少系统调用次数。

  • 2 linux底层文件访问
    每个进程都有一些与之关联的文件描述符,是一些小值整数,可以通过它们访问打开的文件或设备。当一个进程开始运行时,会有三个已经打开的文件描述符。当进程退出后,所有已经打开的文件描述符会自动关闭。
    0:标准输入
    1:标准输出
    2:标准错误

  • 2.1 write系统调用

#include <unistd.h>
size_t write(int fildes,const void* buf,size_t nbytes);

把缓冲区buf前nbytes个字节写入与文件描述符fildes关联的文件中,返回实际写入的字节数。函数返回0,则未写入任何数据,返回-1则表示在write调用中出现错误,错误代码保存在全局变量errno中。

  • 2.2 read系统调用
#include <unistd.h>
size_t read(int fildes,void* buf,size_t nbytes);

从与文件描述符fildes相关联的文件中读入nbytes个字节的数据,并放到数据区buf中,返回实际读入的字节数,返回0表示未读入任何数据,已到达了文件尾,返回-1则表示read调用出现了错误,错误代码保存在全局变量errno中。

  • 2.3 open系统调用
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
int open(const char* path,int oflags);
int open(const char* path,int oflags,mode_t mode);

open系统调用创建一个新文件描述符,建立了一条到文件或设备的访问路径,返回的文件描述符唯一。当文件不存在时,文件打开失败。
oflags中必须指定文件的访问模式:
O_RDONLY只读方式,
O_WRONLY只写方式,
O_RDWR读写方式。
oflags中还可包含下列模式:
O_APPEND写入数据追加在文件尾,
O_TRUNC将文件长度设置为零,
O_CREAT按照阐述mode中设置的访问权限创建文件。
在<limits.h>头文件中的OPEN_MAX定义了可以同时打开的文件数目。
使用带O_CREAT标志的open调用来创建文件时,使用带第三个参数的open函数。文件创建时访问权限的控制,通过mode标志位进行

mode标志位实际上发出设置文件访问权限的请求,与用户掩码的反值做AND操作后,用于创建的文件,即在mode参数中被设置的位如果在umask值中也设置了,那么它就会从文件的访问权限中删除。

  • 2.3.1 umask
    umask是一个系统变量,当文件被创建时,为文件的访问权限设置一个掩码,umask命令可以查看该值。3个数字分别对应用户、组和其他用户的访问权限。
    0:允许任何权限
    4:禁止读
    2:禁止写
    1:禁止执行

  • 2.4 close系统调用

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

用close终止文件描述符fildes与其对应文件之间的关联,文件描述符被释放而能够重新使用。close调用成功时返回0,出错时返回-1。

  • 2.5 ioctl系统调用
#include <unistd.h>
int ioctl (int fildes,int cmd, ...);

ioctl提供一个用于控制设备及其描述符行为的接口,对fildes引用的对象执行cmd参数中给出的操作,根据设备所支持的操作不同,可能会需要第三个参数。

  • 2.6 lseek系统调用
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes,off_t offset,int whence);

lseek系统调用对文件描述符fildes的读写指针位置进行设置。offset参数用来指定位置,而whence参数定义该偏移值的用法,返回从文件头到文件指针被设置处的字节偏移值,失败时返回-1。

whence可以取下列值之一:
SEEK_SET:offset是一个绝对位置
SEEK_CUR:offset是相对于当前位置的相对位置
SEEK_END:offset是相对于文件尾的一个相对位置

  • 2.7 fstat、stat和lstat系统调用
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes,struct stat* buf);
int stat(const char* path,struct stat* buf);
int lstat(const char* path,struct stat* buf);

fstat返回与打开的文件描述符相关的文件的状态信息
stat和lstat返回的是通过文件名查到的状态信息,但当文件是一个符号链接时,lstat返回的是符号链接本身的信息,而stat返回的是该链接指向的文件的信息。
stat结构的成员

代码练习

https://gitee.com/zhang_yu_peng/practice-code/blob/master/代码练习.cpp

原文地址:https://www.cnblogs.com/1208499954qzone/p/15380557.html