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;
}