学习笔记4
- 文件操作
- 使用系统调用进行文件操作
- 实践过程
文件操作
1. 文件操作级别
(1)硬件级别:
- fdisk: 将硬盘、U盘或SDC盘分区
- mkfs: 格式化磁盘分区,为系统做好准备
- fsck:检查和维修系统
- 碎片整理:压缩文件系统中的文件
(2)操作系统内核中的文件系统函数: 前缀 k
表示内核函数
(3)系统调用: 使用系统调用访问内核函数
(4)I/O库函数: C语言提供了一系列标准的I/O库函数
(5)用户命令
(6)sh脚本
2.文件的I/O操作
(1)文件打开和关闭:
- I/O操作的第一步是打开文件。这通过调用操作系统提供的API函数(如C语言中的
fopen
)来完成。打开文件后,系统为该文件分配资源,允许程序读取或写入文件的数据。 - 在文件操作完成后,必须关闭文件以释放资源并确保数据的完整性。关闭文件通常使用
fclose
等函数。
(2)读取数据:
- 读取文件的数据是从文件中获取信息的过程。可以按字节、行或其他数据块的方式进行读取。通常使用
fread
、fgets
等函数来执行读取操作。 - 读取操作需要指定读取位置,通常由文件指针(
file pointer
)管理。文件指针跟踪文件的当前位置,并在每次读取后自动向前移动。
(3)写入数据:
- 写入文件是将数据写入文件的过程。可以按字节、行或其他数据块的方式进行写入。通常使用
fwrite
、fprintf
等函数来执行写入操作。 - 写入操作也需要指定写入位置,通常由文件指针管理。文件指针在写入时自动向前移动。
(4)定位和移动文件指针: 文件指针用于确定文件中的读取或写入位置。可以使用fseek
函数来移动文件指针到文件中的指定位置,以支持随机访问文件。
(5)错误处理: I/O操作可能会遇到各种错误,如文件不存在、权限不足、磁盘空间不足等。程序需要处理这些错误情况,并采取适当的措施,如向用户报告错误或进行错误日志记录。
(6)缓冲: 文件I/O通常使用缓冲来提高性能。读取和写入的数据通常首先存储在内存缓冲区中,然后批量写入磁盘。这减少了磁盘访问的次数,提高了效率。
(7)文本和二进制文件: 文件可以分为文本文件和二进制文件。文本文件包含人可读的字符数据,而二进制文件包含不可打印字符和二进制数据。不同类型的文件需要不同的读写方式。
(8)同步和异步操作: 文件I/O可以是同步或异步的。同步操作会阻塞程序的执行,直到操作完成,而异步操作会允许程序继续执行其他任务。
3. 低级别文件操作:分区
(1)打开终端: 打开Linux终端,以便使用分区工具。可能需要以root用户或具有足够权限的用户身份执行这些操作。
(2)选择分区工具:
fdisk
:这是一个经典的命令行分区工具,适用于专家用户。parted
:这是一个命令行分区工具,提供了更多的分区选项。gparted
:这是一个图形用户界面(GUI)工具,适用于新手用户,更容易使用。
(3)列出可用的磁盘: 在终端中运行以下命令之一,以列出系统中的可用磁盘和分区信息:
fdisk -l
parted -l
(4)选择要分区的磁盘: 根据列出的磁盘信息,选择要进行分区的磁盘,通常以如/dev/sda
或/dev/nvme0n1
之类的形式表示。
(5)创建分区: 使用选定的分区工具创建新的分区,通常有以下步骤:
- 在终端中运行分区工具,如
fdisk /dev/sdX
(/dev/sdX是选择的磁盘)。 - 使用分区工具的命令(如n用于创建新分区)创建分区。需要指定分区的大小、类型、起始位置等信息。
- 根据分区工具的提示,完成分区创建过程。
- 保存分区表:
- 在分区工具中完成分区创建后,不能忘记保存分区表。对于
fdisk
,可以使用w
命令保存。对于parted
,可以使用quit
命令保存。
(6)格式化分区:
创建分区后,需要格式化它以创建文件系统。例如,如果要创建一个ext4文件系统,可以使用以下命令:
mkfs.ext4 /dev/sdXY
其中,/dev/sdXY
是创建的分区的设备名称。
(7)挂载分区: 格式化后的分区需要挂载到Linux文件系统的目录中,以便可以访问其中的数据。可以使用mount
命令手动挂载,也可以将挂载信息添加到/etc/fstab
文件中,以在系统启动时自动挂载。
使用系统调用进行文件操作
1.操作过程
(1)包含头文件: 在C或C++程序中,使用文件操作系统调用之前,需要包含适当的头文件,如 <stdio.h>
、<fcntl.h>
和 <unistd.h>
。这些头文件包含了与文件操作相关的系统调用的声明和常量定义。
(2)文件描述符:
-
在Linux中,每个打开的文件都与一个文件描述符相关联,这是一个整数值。通常情况下,0表示标准输入(stdin),1表示标准输出(stdout),2表示标准错误(stderr)。其他文件描述符用于表示用户打开的文件。
-
使用
open()
系统调用来打开文件,它返回一个文件描述符,用于后续文件操作。
(3)打开文件: 使用 open()
系统调用可以打开文件。它的原型如下:
int open(const char *path, int flags, mode_t mode);
path
是文件的路径。flags
是打开文件的模式,如只读、只写、追加等。mode
是文件的权限(仅在文件不存在时才使用)。
(4)读取文件: 使用 read()
系统调用从已打开文件中读取数据。它的原型如下:
ssize_t read(int fd, void *buf, size_t count);
fd
是文件描述符。buf
是读取数据的缓冲区。count
是要读取的字节数。read()
返回实际读取的字节数,如果达到文件末尾则返回0,如果出现错误则返回-1。
(5)写入文件: 使用 write()
系统调用将数据写入已打开的文件。它的原型如下:
ssize_t write(int fd, const void *buf, size_t count);
fd
是文件描述符。buf
是要写入的数据。count
是要写入的字节数。write()
返回实际写入的字节数,如果出现错误则返回-1。
(6)关闭文件: 使用 close()
系统调用关闭文件,释放文件描述符。它的原型如下:
int close(int fd);
(7)文件定位: 使用 lseek()
系统调用可以移动文件指针,以支持随机访问文件。它的原型如下:
off_t lseek(int fd, off_t offset, int whence);
fd
是文件描述符。offset
是要移动的偏移量。whence
指定偏移量的基准,如文件开头、文件末尾或当前位置。
(8)文件权限和所有权: 使用 chmod()
和 chown()
系统调用可以更改文件的权限和所有者。这些系统调用允许管理文件的访问权限和所有权。
(9)错误处理: 系统调用可能会引发各种错误,如文件不存在、权限不足、磁盘空间不足等。程序需要适当处理这些错误情况,通常通过检查系统调用返回值和 errno 变量来确定是否发生了错误。
(10)同步和异步操作: 文件操作可以是同步或异步的。同步操作会阻塞程序的执行,直到操作完成,而异步操作会允许程序继续执行其他任务。