一.标准IO

先看下区别:文件I/O和标准I/O的区别

1.标准IO介绍

stdio:标准IO,在第五章(优先使用,移植性好)
sysio:系统调用IO,在第三章

例子:
fopen(stdio):
linux下依赖open(sysio),在windows下依赖openfile(sysio)

stdio:FILE类型贯穿始终
fopen(),fclose(),fgetc(),fputc(),fgets(),fputs(),fread(),fwrite(),printf(),scanf(),fseek(),ftell(),rewind(),fflush()

使用man手册:
man 3 fopen (第三章)
man ls
重要的在第七章:man 7 socket, man 7 tcp , man 7 epoll等等

2.fopen函数

在这里插入图片描述
mode参考书本119页

在这里插入图片描述
errno最初是个全局变量,errno参照错误类型:vim /usr/include/asm-generic/errno-base.h
现在errno是一个宏了

3种方法输出错误信息

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

int main() {

	FILE* fp;
	fp = fopen("temp", "r");
	if (fp == NULL) {
		//int fprintf(FILE *stream, const char *format, ...);
		fprintf(stderr, "fopen() failed errno = %d\n", errno);//fopen() failed errno = 2, 错误信息不够直观
		//void perror(const char *s);
		perror("fopen()");			//fopen(): No such file or directory
		//char *strerror(int errnum);
		fprintf(stderr, "fopen(): %s\n", strerror(errno));	//fopen(): No such file or directory
		
		exit(1);
	}
	puts("OK");
	
	exit(0);

}

3.fclose函数

对于函数fopen, FILE* fopen(const char* pathname,…), 其返回的指针必定是函数内在堆区动态分配的,因为如果在栈区,函数返回就失效,如果在静态区static,那fopen多次会被覆盖。一般像fopen,fclose这样成对出现的(逆操作),指针一般就是在堆区。

fclose:
在这里插入图片描述

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

int main() {

	FILE* fp;
	fp = fopen("temp", "w");//可以成功打开,不管是否存在
	if (fp == NULL) {
		//int fprintf(FILE *stream, const char *format, ...);
		fprintf(stderr, "fopen() failed errno = %d\n", errno);
		//void perror(const char *s);
		perror("fopen()");	
		//char *strerror(int errnum);
		fprintf(stderr, "fopen(): %s\n", strerror(errno));
		
		exit(1);
	}
	puts("OK");
	fclose(fp);
	exit(0);

}

如何查看能打开文件最多数目

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

int main() {

	FILE* fp;
	int count = 0;
	while (1) {
		fp = fopen("/home/john/tmp", "r");
		if (fp == NULL) {		
			perror("fopen()");
			break;
		}
		count++;
	}
	
	printf("count = %d\n", count);
	exit(0);
	//输出:
	//Too many open files
	//count = 65532
	//其实还要再加3个 stdin stdout stderr 65535个


}

通过命令ulimit -a可以查看 ulimit -n 可以修改
在这里插入图片描述

4.fgetc和fputc

函数原型:
都是读取单个字符
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);

描述:
在这里插入图片描述
getc是宏,fgetc是函数(宏只占用编译时间不占用调用时间,函数相反),函数会更加稳定安全

函数原型:
都是输出单个字符
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);

描述:
在这里插入图片描述

实现文件复制

#include<stdio.h>
#include<stdlib.h>
/*
	自己实现命令cp
	./linux914.out a.cpp txt

 */
int main(int argc, char** argv) {
	FILE* fps, * fpd;
	int ch;
	if (argc != 3) {
		fprintf(stderr, "Usage:%s <src file> <dst 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) {
		fclose(fps);
		perror("fopen");
		exit(1);
	}
	while (1) {
		ch = fgetc(fps);
		if (ch == EOF) {
			break;
		}
		fputc(ch, fpd);
	}
	fclose(fpd);
	fclose(fps);
	exit(0);
}

统计文件字符个数

#include<stdio.h>
#include<stdlib.h>
/*
	统计文件字符个数
	./linux914.out a.cpp

 */
int main(int argc, char** argv) {
	FILE* fps;
	int count = 0;
	if (argc != 2) {
		fprintf(stderr, "Usage:%s <src file>\n", argv[0]);
		exit(1);
	}
	fps = fopen(argv[1], "r");
	if (fps == NULL) {
		perror("fopen");
		exit(1);
	}
	while (fgetc(fps) != EOF) {
		count++;
	}
	fclose(fps);
	printf("count = %d\n", count);
	exit(0);
}

5. fgets和fputs

fgets:

在这里插入图片描述
return values:

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (’\0’) is stored after the last character in the buffer.

别用gets,它不检查缓冲区长度:

Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.

eg: SIZE = 5
某字符串 “abcd”,用fgets要读两次(最后必须是’\0’)
1: ‘a’,‘b’,‘c’,‘d’,’\0’
2. ‘\n’,’\0’
某字符串 “abcde”,用fgets要读两次(最后必须是’\0’)
1: ‘a’,‘b’,‘c’,‘d’,’\0’
2: ‘e’,\n’,’\0’

fputs:

在这里插入图片描述
在这里插入图片描述
return value:
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
/*
	自己实现命令cp

 */
#define        BUFFSIZE         1024
int main(int argc, char** argv) {
	FILE* fps, * fpd;
	char buf[BUFFSIZE];
	if (argc != 3) {
		fprintf(stderr, "Usage:%s <src file> <dst 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) {
		fclose(fps);
		perror("fopen");
		exit(1);
	}
	while (fgets(buf, BUFFSIZE, fps) != NULL) {
		fputs(buf, fpd);
	}
	fclose(fpd);
	fclose(fps);
	exit(0);
}

6.fread和fwrite

在这里插入图片描述
nmemb:数目
size:单个大小

在这里插入图片描述
返回成功读或写的对象个数(不是读取的字符个数),不够一次的返回0
eg:
假设文件数据量足够:
fread(buf, 1, 10, fp)返回值是10
fread(buf, 10, 1, fp)返回值是1
假设文件数据量只有5:
fread(buf, 1, 10, fp)返回值是5
fread(buf, 10, 1, fp)返回值是0

#include<stdio.h>
#include<stdlib.h>
/*
 	自己实现命令cp

 */
#define BUFFSIZE         1024
int main(int argc, char ** argv){
	FILE* fps,*fpd;
	char buf[BUFFSIZE];
	int n;
	if(argc!=3){
		fprintf(stderr,"Usage:%s <src file> <dst 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){
		fclose(fps);
		perror("fopen");
		exit(1);
	}
	while((n=fread(buf,1,BUFFSIZE,fps))>0){//返回read成功的次数,最后一次是0
		fwrite(buf,1,n,fpd);
	}

	fclose(fpd);
	fclose(fps);
	exit(0);
}

7.printf和scanf族

在这里插入图片描述
fprintf可以指定输出到哪个流
sprintf可以指定一个输出到寄存器(数组)
snprintf指定空间大小
sprintf:

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

/*
 *
	  字符串转整
 *
 */
int main() {

	char str[] = "123456";

	printf("%d\n", atoi(str));//atoi

	char buf[1024];
	int y = 2020, m = 6, d = 24;
	sprintf(buf, "%d-%d-%d", y, m, d);//反atoi
	puts(buf);
	exit(0);

}

在这里插入图片描述

8.fseek和ftell,rewind

fseek,ftell

定位文件指针作用:
在这里插入图片描述

whence:
SEEK_SET:文件首
SEEK_CUR: 当前位置
SEEK_END:文件末尾

有个缺陷:offset是long类型,在32位下是4字节。两个函数合用只能定位2G大小
改进:
在这里插入图片描述

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
off_t一般是32位,如果想变成64位要在makefile中加:
CFLAGS+=-D_FILE_OFFSET_BITS=64
或者gcc 语句最后加-D_FILE_OFFSET_BITS=64

用fseek和ftell统计文件字符数:

#include<stdio.h>
#include<stdlib.h>
/*
	统计文件字符个数

 */
int main(int argc, char** argv) {
	FILE* fps;
	int count = 0;
	if (argc != 2) {
		fprintf(stderr, "Usage:%s <src file>\n", argv[0]);
		exit(1);
	}
	fps = fopen(argv[1], "r");
	if (fps == NULL) {
		perror("fopen");
		exit(1);
	}
	fseek(fps, 0, SEEK_END);
	printf("count = %ld\n", ftell(fps));
	exit(0);
}

rewind

在这里插入图片描述
不管文件指针在哪里,直接定位到开头!

在这里插入图片描述

9.fflush

在这里插入图片描述
在这里插入图片描述

如果参数为NULL,将会刷新所有打开的流

#include<stdio.h>
#include<stdlib.h>
/*
 *
 *缓冲区的作用:大多数情况下是好事,合并系统调用
 *
 *行缓冲: 换行的时候刷新,满了的时候刷新,强制刷新,fflush(标准输出是这样的,因为是终端设备)
 *
 *全缓冲:满了的时候刷新,强制刷新(默认,只要不是终端设备)

* 无缓冲:如stderr,需要立即输出的内容

 * */
int main() {

	printf("before while()");
	fflush(stdout);//不加这一句上面的打印不出来(没有\n)
	while (1);
	printf("after while()");
	fflush(NULL);
}

全缓存、行缓存和无缓存

10.getline

在这里插入图片描述

描述:
getline() reads an entire line from stream, storing the address of the buffer containing the text into *lineptr. The buffer is null-terminated and includes the newline character, if one was found.

代码中为何初始化参数重要:
If *lineptr is set to NULL and *n is set 0 before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.

底层实现:
Alternatively, before calling getline(), *lineptr can contain a pointer to a malloc(3)-allocated buffer *n bytes in size. If the buffer is not large enough to hold the line, getline() resizes it with realloc(3), updating *lineptr and *n as necessary.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char** argv) {

	FILE* fp;
	/*			!!!!初始化值很重要!!!!!		*/	
	char* linebuf = nullptr;
	size_t linesize = 0;
	if (argc < 2) {
		fprintf(stderr, "Usage...\n");
		exit(1);
	}
	fp = fopen(argv[1], "r");
	while (1) {

		if (getline(&linebuf, &linesize, fp) < 0) {
			break;
		}
		else {
			printf("%d\n", strlen(linebuf));
			printf("%d\n", linesize);//打印系统给你分配的单次malloc字符数目,这里都是120,当一行字符要超过120,它会realloc,增大linesize值
		}
	}
	fclose(fp);
	exit(0);

}

11.临时文件

1.如何不冲突
2.及时销毁
Linux下使用tmpnam()和tempnam()创建唯一的包含路径的临时文件名

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值