标准IO

I/0 是一切实现的基础,可以通过stdio或通过sysio直接对话kernel
stdio 标准io(优先使用):合并系统调用sysio, FILE类型贯穿始终
sysio 系统调用io(文件io)

基本操作

  • fopen、 fclose 文件打开、关闭

  • fgetc、fputc、fgets、fputs 字符、字符串读写

  • fread、write、printf、scanf

    fgets() 遇到 size-1 or ‘\n’停止
    fgets() 返回字符串或者null
    fgets(buf, 5, stream) 读abcd要读几次?
    1)a b c d ‘\0’ 2)’\n’ ‘\0’

  • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    从stream读,写到ptr,读nmemb * size个字节

  • size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
    读ptr,写到stream

  • FILE *fopen(const char *pathname, const char *mode)

    FILE * 在堆上(malloc动态空间)、fclose(free)
    最多能打开文件个数:
    ulimit -a
    open files (-n) 1024
    stream:stdin、stdout、stderr

  • FILE *fdopen(int fd, const char *mode)

  • FILE *freopen(const char *pathname, const char *mode, FILE *stream)

mode含义
r
w写,有则情况,无则创建
a追加,无则创建
r+读写
w+读写,无则创建
a+追加,无则创建读使指针在第一个有效字节处,追加指针在最好一个有效字节的下一位
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main()
{
	FILE *fp;
	
    fp = fopen("tmp", "r");
	if (fp == NULL) {
		//fprintf(stderr, "fopen() fail %d\n", errno);
		perror("fopen()");
		//fprintf(stderr, "fopen() fail %s\n", strerror(errno));
		exit(1);
	}
	puts("ok");
	fclose(fp);
	exit(0);
}

errno

vim /usr/include/asm-generic/errno-base.h
errno->err msg:
void perror(const char *s);
char *strerror(int errnum);

实现文件拷贝功能

cp 的fgetc/fputc版本

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
	FILE *fps, *fpd;
	int ch;
	
	if (argc < 3) {
		fprintf(stderr, "usage:%s <src_file> <dest_file>\n", argv[0])
		exit(1);
	}
	
	fps = fopen(argv[1], "r");
	if (fps == NULL) {
		perror("fopen()");
		exit(1);
	}
	fpd = fopen(argv[2], "w");
	if (fpd == NULL) {
		perror("fopen()");
		fclose(fps);
		exit(1);
	}
	
	while(1) {
		ch = fgetc(fps);
		if (ch == EOF) {
			break;
		}
		fputc(ch, fpd);
	}
	fclose(fpd);
	fclose(fps);
	
	exit(0);
}

  ./mycpy src dst

cp 的fgets/fputs版本、fread/fwirte版本

#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 1024
int main(int argc, char **argv)
{
	FILE *fps, *fpd;
	char buf[BUFSIZE];
	
	if (argc < 3) {
		fprintf(stderr, "usage:%s <src_file> <dest_file>\n", argv[0])
		exit(1);
	}	
	fps = fopen(argv[1], "r");
	if (fps == NULL) {
		perror("fopen()");
		exit(1);
	}
	fpd = fopen(argv[2], "w");
	if (fpd == NULL) {
		perror("fopen()");
		fclose(fps);
		exit(1);
	}	
	while(fgets(buf, BUFSIZE, fps) != NULL) {
		fputs(buf, fpd);
	}
 /*
 	while(n = fread(buf, 1, BUFSIZE, fps) > 0) {
		fwrite(buf, 1, n, fpd);
	}
 */
	fclose(fpd);
	fclose(fps);
	
	exit(0);
}

fgetc 测试文件有效字符个数

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
	FILE *fp;
	int count;
		
	if (argc < 2) {
		fprintf(stderr, "usage...\n")
		exit(1);
	}
	
	fp = fopen(argv[1], "r");
	if (fp == NULL) {
		perror("fopen()");
		exit(1);
	}
	while (fgetc(fp) != EOF) {
		count++;
	}
	printf("count = %d\n", count);	
	fclose(fp);
	
	exit(0);
}

  ./getnum file

打印与输入

  • 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, …)

  • int atoi(const char *nptr)

  • long atol(const char *nptr)

  • long long atoll(const char *nptr)

char str[] = "123a456"
atoi(str)   123
char buf[1024];
sprintf(buf, "%d-%d-%d", year, month, day);
puts(buf);
  • int vprintf(const char *format, va_list ap)

  • int vfprintf(FILE *stream, const char *format, va_list ap)

  • int vdprintf(int fd, const char *format, va_list ap)

  • int vsprintf(char *str, const char *format, va_list ap)

  • int vsnprintf(char *str, size_t size, const char *format, va_list ap)

  • int scanf(const char *format, …)

  • int fscanf(FILE *stream, const char *format, …)

  • int sscanf(const char *str, const char *format, …)

操作文件位置指针

文件指针,就像读书时眼睛移动一样,文件指针逐行移动
什么时候用?对一个文件先读后写的时候,比如:
FILE *fp = fopen();
fputc(fp);
fgetc();//无法得到刚刚写入的东西

  • int fseek(FILE *stream, long offset, int whence)
    设置文件指针位置 offset是偏移位置

  • whence is set to SEEK_SET, SEEK_CUR, or SEEK_END
    long ftell(FILE *stream);
    返回文件指针位置

  • int fseek(FILE *stream, long offset, int whence);

  • long ftell(FILE *stream);

    fseek(fp, 0, SEEK_END);
    ftell(fp); 获得文件大小
    

    fseek long offset -2G ~ 2G
    ftell return long 0 ~ 2G (2的31次方)
    注意使用fseek和ftell时,文件大小有限制

  • void rewind(FILE *stream);
    使得文件指针回到文件开始位置,相当于(void) fseek(stream, 0L, SEEK_SET)

  • int fseeko(FILE *stream, off_t offset, int whence);

  • off_t ftello(FILE *stream);

    On some architectures, both off_t and long are 32-bit types, but
    defining _FILE_OFFSET_BITS with the value 64 (before including any header files) will turn off_t into a 64-bit type
    makefile:
    CFLAGS+=-D_FILE_OFFSET_BITS=64

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main()
{
    const int SIZE = 1024;
    FILE *fp = NULL;
    char buf[SIZE];
    buf[0] = 'A';
    buf[1] = 'A';
    buf[2] = 'A';
    buf[3] = 'A';

    fp = fopen("./tmp","w+");
    if (fp == NULL){
        strerror(errno);
        exit(1);
    }
    
    int i = 0;
    while(i < 10){
        unsigned long n = fwrite(buf,1,4,fp);
        fseek(fp,-n,SEEK_CUR);
        unsigned long len =  fread(buf,1,n,fp);
        printf("%lu\n",len);
        fseek(fp,0,SEEK_END);
        i++;
    }
    
    fseek(fp,1024,SEEK_CUR);
    return 0;
}
  • -int fgetpos(FILE *stream, fpos_t *pos);
  • int fsetpos(FILE *stream, const fpos_t *pos);

刷新缓存

  • int fflush(FILE *stream);

    缓冲区的作用:合并系统调用
    行缓冲:换行时刷新、满了时刷新、强制刷新(标准输出,因为是终端设备)
    全缓冲:满了时刷新、强制刷新(默认,只要不是终端设备)
    无缓冲:如stderr(需要立即输出的内容)

读取一行

  • ssize_t getline(char **lineptr, size_t *n, FILE *stream);

    从流中读取一行,保存buffer的首地址到 *lineptr,返回大小n
    成功则返回成功读到的字符个数(包含分隔符:空格、回车…),不包含最后的空字符
    失败返回-1
    先alloc,然后不断的realloc,存在内存泄漏

  • ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);

    makefile:
    CFLAGS+=-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
    

获取文件每一行的有效字符数

int main(int arg, char **argv)
{
	FILE *fp;
	char *linebuf;
	size_t linesize;
	
	if (argc < 2) {
		fprintf(stderr, "Usage...\n");
		exit(1);
	}
	
	fp = fopen(argv[1], "r");
	if (fp == NULL) {
		perror("fopen()");
		exit(1);
	}
	
	/* notice!!! */
	linebuf = NULL;
	linesize = 0;
	
	while(1) {
		if (getline(&linebuf, &linesize, fp) < 0) {
			break;
		}
		printf("%d\n", strlen(linebuf));
		printf("%d\n", linesize);
	}
	
	fclose(fp); 
	
	exit(0);
}

临时文件

1、如何不冲突 2、即时销毁

  • char *tmpnam(char *s);
    create a name for a temporary file
    需要2步,产生名字,创建文件,无法保证线程安全

  • FILE *tmpfile(void);
    create a temporary file,匿名文件

    The tmpfile() function opens a unique temporary file in binary read/write (w+b) mode.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main()
{
    FILE *tmpfp;
    tmpfp = tmpfile();

    const char* oribuf = "2020/12/25";
    int SIZE = 0;
    while(*(oribuf+SIZE) != 0){
        SIZE++;
    }
    printf("%d\n",SIZE);
    
    fwrite(oribuf,1,SIZE,tmpfp);
    fseek(tmpfp,0,SEEK_SET);
    

    FILE *fp;
    fp = fopen("tmp","w");
    char desbuf[SIZE];
    int n = fread(desbuf,1,SIZE,tmpfp);
    fwrite(desbuf,1,n,fp);

    fclose(tmpfp);
    fclose(fp);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值