当前位置: 首页 > news >正文

linux系统编程06-标准IO2

目录
  • printf\scanf函数族
  • fseek\ftell\rewind
  • getline
  • 临时文件

printf\scanf函数族

printf一族: man 3 printf

int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);

printf 是把待输出内容 ... 按照指定格式 format 输出到 stdout 中。

fprintf 则可指定输出的位置,默认 stdoutstderr 指向屏幕, stdin 指向键盘。

sprintf将不同类型的数据综合成一个串

snprintf 则解决 sprintf 没有指定缓冲区大小的问题,类似 fgetsgets

相比于 printf ,其他函数更常用。

sprintf() 应用举例: atoi 实现把串转换为整数【串结束和碰到非数字字符时停止】,但是c中并没有 itoa 即把整型转换为一个串,,用 sprintf 可以实现这一点。

示例代码:

##include<stdio.h>
##include<stdlib.h>int main()
{char s[] = "123a456";printf("%d\n", atoi(s));char buf[1024];int year = 2022, month = 12, day = 28; sprintf(buf, "%d-%d-%d", year, month, day);puts(buf);exit(1);
}

运行结果:

Untitled

scanf一族: man 3 scanf

int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);

scanfstdin 中获取内容,按照 format 格式,填充到变量 ... 中。

fscanf 则可指定从哪个stream中获取内容。

sscanf 则从字符串 str 中获取内容,可以理解为 sprintf 的逆过程,把一个字符串按格式拆分为不同类型。【功能包含了 atoi

sscanf 例子:

示例代码:

##include<stdio.h>
##include<stdlib.h>int main()
{char s[] = "123a456";int x1, x2; sscanf(s, "%da%d", &x1, &x2);printf("%d %d\n", x1, x2); exit(1);
}

运行结果:

Untitled

fseek\ftell\rewind

int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);

fseek :设置文件指针的位置

  • 参数:流、偏移、基本位置( SEEK_SET SEEK_CUR SEEK_END 文件头,当前位置,文件尾)
  • 返回值: 0表示设置成功,1表示设置失败

ftell :判断当前文件指针的位置

  • 参数:流
  • 返回值:相对于开头的位置

rewind :将文件指针重置到开头,相当于 fseek(stream, 0, SEEK_SET)

fseekftell 使用举例:

//1. 读取10个字节并输出
fp = fopen();
fgetc(fp) * 10 -> rewind/fseek(fp,0,SEEK_SET) -> fput()//2. fseek可以用来产生空洞文件//3. fseek和ftell判断文件大小
##include<stdio.h>
##include<stdlib.h>int main(char argc, char **argv)
{if(argc < 2){   fprintf(stderr, "Usage: %s <file_name>", argv[0]);exit(1);}   FILE *fp;int cnt = 0;fp = fopen(argv[1], "r");if(fp == NULL){   perror("fopen()");exit(1);}   fseek(fp, 0, SEEK_END);printf("%ld\n",ftell(fp));       /*    while(fgetc(fp) != EOF)cnt++;printf("cnt = %d\n", cnt);
*/fclose(fp);exit(0);
}

运行结果:

Untitled

fflush :刷新缓冲区

int fflush(FILE *stream);
  • 参数:流,如果填NULL,表示刷新所有打开的流

缓冲区的作用:大多数情况下是好事,合并系统调用

三种缓冲方式:

  1. 行缓冲:换行刷新、满了刷新、强制刷新【 stdout ,因为是终端设备】
  2. 全缓冲:满了刷新、强制刷新【默认,只要不是终端设备】
  3. 无缓冲:如 stderr ,需要立即输出的内容

现象:什么都不打印,因为缓冲区没有刷新

int main()
{int i;printf("Before while()");while(1);printf("After while()");exit(0);
}

现象:打印 “Before while()”,因为缓冲区刷新了

int main()
{int i;printf("Before while()\n");/*printf("Before while()");fflush(stdout); or fflush(NULL)*/while(1);printf("After while()\n");exit(0);
}

fseek和ftell的缺陷:二者同时使用的时候由于ftell只能返回long类型的正数部分,而long类型的大小不同机子上定义不同,一般是2G-1(32bit),所以两个函数最多只能操作2G大小

fseeko,ftello用一个自定义类型解决了这个问题,但是不支持C89,C99,是方言,所以移植性不足

使用时要在编译时加 _FILE_OFFSET_BITS=64

Untitled

写法如 gcc a.c -o a -D_FILE_OFFSET_BITS=64 太麻烦,写入makefile中

##终端执行
vim makefile
##makefile中写入
CFLAGS += -D_FILE_OFFSET_BITS=64

如果要移植性好又要支持大文件,就得另想办法

getline

具有一个不可替代性:获取一行的大小,而无需在意该行有多大

内部实现:malloc,如果不够再realloc,从而取到足够大的空间来存储读取到的数据

ssize_t getline(char **lineptr, size_t *n, FILE *stream);
  • 参数:
    • lineptrchar * 的地址,作为缓冲区
    • nsize_t 的地址,getline会反填n,表示 lineptr 已分配的大小
  • 返回值:成功0,失败-1

例子:获取文件每一行的大小,并打印

示例代码:

##include<stdio.h>
##include<stdlib.h>
##include<string.h>int main(int argc, char **argv)
{if(argc < 2){   fprintf(stderr, "Usage:...\n");exit(1);}   FILE *fp;char *linebuf;size_t linesize;fp = fopen(argv[1], "r");if(fp == NULL){   perror("fopen()");exit(1);}   //很重要!!!linebuf = NULL;linesize = 0;while(1){   if(getline(&linebuf, &linesize, fp) < 0)break;printf("%d\n", (int)strlen(linebuf));printf("%d\n", (int)linesize);}   fclose(fp);exit(0);
}

运行结果:

Untitled

*getline 存在可控的内存泄漏问题,因为它没有互逆操作来 freelinebuf 的内存*

临时文件

//临时文件:
1. 名字如何不冲突
2. 及时销毁char* tmpnam(char *s);
FILE* tmpfile();

tmpnam 产生一个可用的临时文件名,然后我们拿这个文件去创建临时文件。

可以看书拿到文件名和创建文件是分两步的,中间可能会被打断,所以存在 并发问题 ,比如进程A执行 tmpnam 后没来得及创建文件,就轮到进程B执行了, 而进程B同样执行了 tmpnam ,由于进程A执行 tmpnam 后没有创建文件,所以系统认为 进程A中 tmpnam 返回的文件名仍是可用的,于是返回给了进程B,然后进程B创建文件,就会导致进程A的名字冲突。

tmpfile:产生匿名文件,返回它的 FILE*

  • 匿名文件:存在于磁盘但无法查看也无法 ls -a 查看的文件
  • fclose 后,匿名文件会自动销毁【硬链接为0,文件计数符为0】
  • 如果忘记 fclose :可控内存泄漏【如果程序 exitreturn 正常结束,进程申请的空间会被释放】
http://www.wxhsa.cn/company.asp?id=6129

相关文章:

  • linux系统编程08-高级IO
  • 第03周 预习、实验与作业:面向对象入门2与类的识别
  • 第8篇、Kafka 监控与调优实战指南
  • linux系统编程02-进程基本知识
  • linux系统编程03-并发:信号
  • linux系统编程04-并发:线程
  • 新手高效制作PPT的3个步骤:告别逻辑混乱,从构思到完成!
  • Avalonia:用 ReactiveUI 的方法绑定数据、事件和命令
  • 【pyQT 专栏】程序设置 windows 任务栏缩略图(.ico)教程
  • Say 题选记(9.14 - 9.20)
  • vm的配置
  • 力扣72题 编辑距离
  • 数学基本结构框架
  • 2025.9.16总结
  • 在 Tailscale 中禁用 DNS
  • 软件工程实践一:Git 使用教程(含分支与 Gitee)
  • 【青少年低空飞行玩意】设计图以及项目概况
  • C++ 多态
  • Python实现对比两个Excel表某个范围的内容并提取出差异
  • 我用AI给自己做了一整套专属表情包!攻略
  • 20250916 之所思 - 人生如梦
  • Vue3项目开发专题精讲【左扬精讲】—— 在线教育网站系统(基于 Vue3+TypeScript+Vite 的在线教育网站系统系统设计与实现)
  • 20250915
  • Python Socket网络编程(4)
  • 今日学习 dos命令和Java基础语法
  • Photoshop 2025 v26.0软件下载免费版安装教程(含 Photoshop 软件一键安装包免费下载渠道)
  • 课前问题列表
  • switch中初始化变量
  • office2024免费永久激活安装包下载安装教程包含(下载安装配置激活)
  • vue2和vue3一时转不过来