【Linux系统编程】文件IO 标准IO

一,printf和scanf函数

1,printf一族函数

printf是按照对应的format进行输出的,输出是放在终端的

fprintf是按照对应的流,将这个格式输出到对应的流里面
(这个函数可以将对应的报错和警告输入到对应的文件里面,不输出到终端,这样更加清楚观看)

sprintf是按照这个格式,将此放到对应的字符数组里面

snpritf是为了解决这个sprintf不检查这个数组溢出的问题的,防止数组越界

2,重定向的概念

(1)、核心概念铺垫

在 Linux/UNIX 系统中,每个进程默认打开 3 个文件描述符(可以理解为 "文件句柄"):

  • 0 (stdin):标准输入(默认是键盘)
  • 1 (stdout):标准输出(默认是终端屏幕)
  • 2 (stderr):标准错误(默认也是终端屏幕,用于输出错误信息)

重定向的本质就是:改变这 3 个描述符的默认指向(比如从屏幕改成文件)。

(2)、常用重定向符号及用法

1. 标准输出重定向 > / >>

表格

符号 作用 示例 说明
> 覆盖式重定向 echo "hello" > /tmp/out.txt echo的输出写入out.txt如果文件已存在会清空原有内容
>> 追加式重定向 echo "world" >> /tmp/out.txt 将内容追加到文件末尾,不会清空原有内容

注意:> 等价于 1>(显式指定 stdout),比如 ls -l 1> /tmp/ls.txtls -l > /tmp/ls.txt 效果完全一样。

2. 标准错误重定向 2> / 2>>

表格

符号 作用 示例 说明
2> 覆盖式重定向错误 ls /nonexist 2> /tmp/error.txt ls的错误信息写入error.txt,覆盖原有内容
2>> 追加式重定向错误 cat /fakefile 2>> /tmp/error.txt 将错误信息追加到文件末尾
3. 同时重定向标准输出和标准错误

这是最常用的场景(比如把命令的正常输出和错误都保存到文件):

  • 方式 1(推荐,兼容所有 shell):command > /tmp/all.log 2>&1
    • 解释:2>&1 表示 "把 stderr(2)重定向到 stdout(1)当前指向的位置"(也就是/tmp/all.log
  • 方式 2(bash/zsh 简化写法):command &> /tmp/all.log
    • 解释:&> 等价于 > file 2>&1,更简洁
  • 追加写法:command >> /tmp/all.log 2>&1command &>> /tmp/all.log

示例:

bash 复制代码
# 把ls的正常输出和错误都追加到日志文件
ls /etc /nonexist >> /tmp/ls_all.log 2>&1
4. 标准输入重定向 <

表格

符号 作用 示例 说明
< 重定向标准输入 cat < /tmp/out.txt catout.txt读取内容,而不是键盘
<< 此处文档(Here Document) cat << EOF > /tmp/hello.txt Hello World EOF 输入到EOF为止的内容,写入hello.txt(常用于脚本中写多行内容)

示例(用<实现批量输入):

bash 复制代码
# 把文件内容作为输入传给wc命令(统计行数)
wc -l < /etc/passwd

3,scanf一族函数

fscanf就是将特定流的东西按照这个格式放到对应的地址

sscanf就是将这个字符串按照对应的格式放到对应的地址
注意这个是没有限制大小的,所以无法预测这个大小是否匹配会出现问题

二,fseek和ftell函数

1,fseek函数

fseek函数是用来修改文件指针的位置的。

当用fopen()打开文件后,系统会为这个文件分配一个文件指针 (不是FILE*类型的指针变量,而是记录当前读写位置的 "游标"):

  • 默认情况下,刚打开文件时,指针指向文件开头;
  • 每读写一个字节,指针会自动向后移动 1 位;
  • fseek()的作用就是手动修改这个指针的位置,实现 "跳着读 / 写" 文件。
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *fp = fopen("test.txt", "r");
    if (fp == NULL) {
        perror("fopen failed");
        exit(1);
    }

    // 先读2个字符,指针会自动后移
    char c1 = fgetc(fp);
    char c2 = fgetc(fp);
    printf("读取前2个字符:%c%c\n", c1, c2);

    // 用fseek跳回文件开头(基准是SEEK_SET,偏移0)
    fseek(fp, 0, SEEK_SET);
    // 重新读第一个字符,验证指针位置
    char c3 = fgetc(fp);
    printf("跳回开头后读取的字符:%c\n", c3);

    fclose(fp);
    return 0;
}

打开一个名为test.txt的文件,先读取前两个字符,然后通过fseek()把文件指针跳回文件开头,再重新读取第一个字符,以此验证fseek()确实能手动调整文件读写指针的位置

2,ftell函数

这个是用来返回文件位置指针的位置在哪里位置的

返回值为long

3,long类型问题

文件位置指针的位置不可能为负数,只可以为正数

由于在32为机器里面,long为有符long类型,范围为-2^31 ~ 2^31,那么这个这个缺陷就很明显,这个文件的大小不可以超过2G,所以为此又有了fseeko和ftello解决这个问题,但是这个适合在linux里面,所以移植性差,但是fseek和ftell的移植性好


这里说,这个off_t,在不同情境下的位数不一样,要想扩大至64位数,在编译的适合就要将

_FILE_OFFSET_BITS = 64编译进去,这样无论在什么情境下都是由64位的

三,文件位置函数和缓冲区刷新函数

1,文件位置函数

fseek函数是用来修改文件指针的位置的。

ftell函数用来返回文件位置指针的位置在哪里位置的。

然后fseek函数有三种方式

  1. SEEK_SET 表示文件的开头

  2. SEEK_CUR 表示文件的当前位置

  3. SEEK_END 表示文件的末尾

fseek(fp, 0, SEEK_SET); 流,偏移量,当前位置

ftell也可以用于查看文件大小,跳到最后一行,然后一查看就知道有多少字节数。

2,下载软件的机制

下载软件首先会创建一个空洞文件,比如要下载的文件大小为2G,那么这个空洞文件大小也为2G,然后这里面存放的全部都是/0,然后使用多进程来讲文件全部写入到这个空洞文件完成下载。

3,缓冲刷新函数

缓冲的三种机制

1,行缓冲机制:换行的时候就进行刷新缓冲 (如这个标准输出就是)

2,全缓冲机制:要等缓冲满了才进行刷新缓冲(这个是文件默认的)

3,无缓冲进制:强制刷新缓冲(这个比如fflush函数就会这样)

不难看到第一行是没有打印出来得,如果在输出后面加一个换行或者ffluhs(NULL)就可以输出出来了

然后厘米是NULL得话就表示全部打开的流都刷新一遍

四,getline函数

getline函数是用malloc函数先创建一个空间,然后如果这个空间大小不够的话,那就要用relloc来扩展这个空间大小,直到可以装下。

1,bug问题

getline函数里面的要有对应的这个行创建的一个空间,然后后面就开辟一个n的初始大小的空间,然后获取这个行在哪一个流stream里面

这里面的lineptr指针和n是需要进行初始化的,如果没有进行初始化就会产生bug

因为这个不进行初始化,就无法判断这个是否是第一次用,那么就会里面的封装的方法就会出现bug,导致计算出来数据不对

2,可控的内存泄露

getline的实现就是用malloc创建空间,然后用relloc来进行衔接内存大小,在此过程中是没有释放这个内存的,所以这个时候就会产生内存泄露,这里不建议释放,因为你不知道这个内置函数的方法是怎么实现的,比如这里面如果用new,就要用delete来进行释放才可以。我们也可以自己修改一下这个函数使得这个函数好用

相关推荐
郝学胜-神的一滴1 小时前
Python中的del语句与垃圾回收机制深度解析
服务器·开发语言·网络·python·算法
EverydayJoy^v^2 小时前
Linux Shell 高级编程(2)——sed
linux·运维·服务器
小义_2 小时前
【Kubernetes】(二)k8s基础
linux·云原生·k8s
Java后端的Ai之路2 小时前
在一个 Python 脚本中导入另一个脚本的功能
服务器·开发语言·python
清水白石0082 小时前
《解锁 Python 潜能:从异步基石到 pytest-asyncio 高级测试实战与最佳实践》
运维·python·pytest
三无少女指南2 小时前
开发者环境配置最佳实践:编辑器Cursor ,VS Code的上位体验实现 AI 与 WSL 联动
运维·c语言·数据库·windows·git·编辑器
2301_805348972 小时前
Haproxy的介绍以及配置示例
运维
BHXDML2 小时前
VMware 安装 Ubuntu 24.04 详细步骤
运维·服务器·ubuntu
Pr Young2 小时前
有限状态机
服务器·后端