Linux系统IO相关函数

标准IO

#include <stdio.h>
//stdio:标准的输入输出	标准IO
printf/scanf//就是标准IO的接口

文件IO和标准IO

文件IO:是系统调用

标准IO:是库函数

系统调用和库函数

  • 系统调用
    • 从用户空间进入内核空间的一次过程就是一次系统调用
    • 系统调用没有缓冲区,效率比较低。系统调用的可移植性比较差
  • 库函数
    • 库函数 = 缓冲区 + 系统调用
    • 效率比系统调用的高,可移植性高

标准IO和文件IO的常用接口

  • 文件IO:open read write close ...
  • 标准IO:printf scanf fopen fread fwrite fclose

标准IO

  • FILE指针

    • FILE是一个结构体,fopen函数的返回值是FILE的指针,这个FILE指针记录了打开文件的所有的信息以后在操作文件的时候就通过FILE完成

    • typedef struct _IO_FILE FILE;

    •   struct _IO_FILE 
        {
        	char* _IO_buf_base;	//缓冲区的起始地址
        	char* _IO_buf_end;	//缓冲区的结束地址
        	...
        }
      
    • 在一个正在运行的程序中默认已经产生了三个FILE指针

      • stdin:标准输入
      • stdout:标准输出
      • stderr:标准出错

标准IO常用函数

fopen函数

  •   #include <stdio.h>
      FILE *fopen(const char *pathname, const char *mode);
    
  • 功能:使用标准IO接口打开文件,在用户空间申请一片缓冲区

  • 参数:

    • 文件的路径和名字

    • 打开文件的方式

      • 参数功能
        r只读方式打开文件,光标定位到文件开头
        r+以读写方式打开文件,光标定位到文件开头
        w有则清空,无则创建,以只写的方式打开文件,光标定位到文件开头
        w+有则清空,无则创建,以读写的方式打开文件,光标定位到文件开头
        a无则创建,以追加的方式打开文件,光标定位到文件末尾
        a+无则创建,以读和追加的方式打开文件,读则开头,尾则结尾
      • 返回值

        • 成功:返回FILE*类型
        • 失败:返回NULL,更新errno(错误码)
        • 不同的错误,errno不同

perrop

  • 功能:根据errno打印对应的错误信息

  • 原型:

    •   #include <stdio.h>
        void perror(const char *s);
      
  • 参数:char *s用于提示的字符串

    • 例如:函数名 error:

strerror

  • 功能:将给定的错误码,变成对应的字符串信息

  • 原型

    •   #include <string.h>
        char *strerror(int errnum);
      
  • 参数:错误码

  • 返回值

    • 成功:指定错误码信息
    • 失败:Unknown error nnn

errno错误码头文件

#include <errno.h>

fclose

  • 功能:关闭文件,同时释放缓冲区等其他资源;(关闭文件描述符)

  • 原型:

    •   #include <stdio.h>
        int fclose(FILE *stream);
      
  • 参数:FILE *stream:指定关闭哪个文件

  • 返回值:

    • 成功:返回0
    • 失败:返回EOF,更新errno
      • #define EOF (-1)

fprintf

  • 功能:将数据输出到指定的文件中

  • 原型

    •   #include <stdio.h>
        int printf(const char *format, ...);
        int fprintf(FILE *stream, const char *format, ...);
      
  • 参数:

    • FILE *stream:指定要输出到哪个文件中,填上对应的流指针
    • char *format:格式化字符串,其中可以填字符,占位符,转义符等等
    • …:不定参数,不定数据类型,不定数据个数
  • 返回值:

    • 成功:返回成功输出的字符个数
    • 失败:返回负数

fscanf

  • 功能:从指定的文件中以格式化获取数据,%d %s %f不会获取空格和换行,%c可以获取空格和换行字符

  • 原型:

    •   #include <stdio.h>
        int scanf(const char *format, ...);
        int fscanf(FILE *stream, const char *format, ...);
      
  • 参数:

    • FILE *stream:指定要从哪个文件中读取数据;
    • char *format:格式化输出字符串:占位符
    • …:不定参数,不定数据类型,不定数据个数
  • 返回值:

    • 成功:返回成功读取到的数据个数

    • =EOF:不更新errno,文件读取到结尾; errno == 0;

    • =EOF:更新errno,函数运行失败

fputc

  • 功能:将单个字符输出到指定的文件中

  • 原型

    •   #include <stdio.h>
        int fputs(int c, FILE *stream);
        int putchar(int c);
      
  • 参数:

    • FILE *stream:指定要将字符输出到哪个文件中,填上对应的流指针
    • int c:指定要输出的字符对应的整型形式,或者字符形式
  • 返回值:

    • 成功:返回成功输出的字符对应的整型形式
    • 失败:EOF

fgetc

  • 功能:从指定的文件中读取单个字符

  • 原型:

    •   #include <stdio.h>
        int fgetc(FILE *stream);
        int getchar(void);
      
  • 参数:

    • FILE *stream:指定要从哪个文件中读取数据
  • 返回值:

    • 成功:返回成功读取到的字符对应的整型形式
    • 失败:EOF
    • 读取完毕:EOF

fseek

如果偏移量在文件开头的时候,不允许继续向前偏移

如果偏移量在文件结尾的时候,允许继续往后偏移。且偏移后写入数据,前面偏移部分内容会自动补0对应的字符形式就是^@

  • 功能:修改文件偏移量(可以理解成是修改光标所在位置)

  • 原型:

    •   #include <stdio.h>
        int fseek(FILE *stream, long offset, int whence);
      
  • 参数:

    • FILE *stream:指定要修改哪个文件的偏移量

    • long offset:偏移量,新的位置尾whence加上offset参数

      ​ 若想往结尾偏移,则填正数

      ​ 若想往开头便宜,则填负数

    • int whence

      • SEEK_SET//文件开头
      • SEEL_CUR//文件当前位置
      • SEEK_END//文件结尾位置
  • 返回值:

    • 成功:返回0
    • 失败:返回-1,更新errno

rewind

  • 功能:将文件偏移量修改到文件开头

  • 原型:

    •   #include <stdio.h>
        void rewind(FILE *stream);
        void fseek(FILE *stream, 0, iSEEK_SET);
      

ftell

  • 功能:获取文件当前位置距离文件开头的偏移量

  • 原型:

    •   #include <stdio.h>
        long ftell(FILE *stream);
      
  • 参数:

    • FILE *strem:指定要获取哪个文件的偏移量
  • 返回值:

    • 成功:返回文件当前位置距离开头的偏移量
    • 失败:返回-1,更新errno
//获取文件大小
fseek(fp, 0, SEEK_END);
size = ftell(fp);
printf("size = %ld\n", size);

fputs

  • 功能:将字符串输出到指定的文件中,与puts的区别:打印的字符串不会自动补’\n’

  • 原型:

    •   #include <stdio.h>
        int fputs(const char *s, FILE *stream);
        int puts(const char *s); 
        puts(str);
      
  • 参数:

    • const char *s:指定要输出的字符串的首地址
    • FILE *stream:指定要输出到哪个文件夹中
  • 返回值:

    • 成功:返回非负数(字符串长度)
    • 失败:EOF

fgets

  • 功能:从指定的文件中获取字符串

    • fgets读取完’\n’字符后,会停止读取,遇到EOF即文件结尾,也会停止读取
    • fgets读取数据完毕后,会在读取的有效字符后面自动补充’\0’字符,sizeof()获取长度需要减一
  • 原型:

    •   #include <stdio.h>
        char *fgets(char *s, int size, FILE *stream);
      
  • 参数:

    • char *s:存储获取到的字符串
    • int size:指定一次最多获取多少个:size-1个
    • FILE *stream
  • 返回值:

    • 成功:返回存储获取到的数据的内容数组首地址
    • 失败或者读取到文件结尾,返回NULL

fwrite

  • 功能:将数据的二进制形式写入到文件中

    • 二进制形式:会将数据拆分成一个一个的字节,并将字节转换成字符形式,写入到文件中
  • 原型:

    •   #include <stdio.h>
        size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
      
  • 参数:

    • void *ptr:任意类型指针,该指针的内存空间中存放着要输出的数据首地址,它可以输出任意类型数据
    • size_t size:每个数据的大小,以字节为单位
    • size_t nmemb:指定要输出多少个数据
    • FILE *stream
  • 返回值:

    • 成功:返回指定要输出的数据个数
    • 失败:小于指定要输出的个数,或者等于0
    int arr[3] = {1, 2, 3};
    fwrite(arr, 4, 3, fp); ==>返回3
    fwrite(arr, sizeof(arr), 1, fp); ==>返回1
    

fread

  • 功能:将数据的二进制形式从文件中读取出来,并转换成指定类型数据

  • 原型:

    •   #include <stdio.h>
        size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
      
  • 参数:

    • void *ptr:任意类型指针,该指针指向的内存空间中,存储读取到的数据。它可以读取任意类型的数据
    • size_t size:每个数据的大小,以字节为单位
    • size_t nmemb:指定要读多少个数据
    • FILE *stream
  • 返回值:

    • 成功:返回指定要读取的数据个数
    • 失败:小于指定要读取的数据个数,或者等于0
  • 使用建议

    • 因为每次读取的数据不满足函数参数需要读取的数据就会读取失败
    • 所以建议每次读取一个数据,因为任何数据都是1的倍数,或者一次读取一个字节,这样就可以避免读取失败
      • fread(arr, sizeof(int), 1, fp);一次读取1个数据,每个数据大小为4字节
      • fread(arr,1,sizeof(arr), fp);一次读取sizeof(arr)个数据,每个数据大小为1字节

sprintf

  • 功能

    • 在给定的字符数组str中,存入一个格式串
  • 原型

    •   #include <stdio.h>
        int sprintf(char *str, const char *format, ...);
      
  • 参数

    • char *str:字符数组容器
    • const char *format:格式串,可以包含格式控制符
    • ...:可变参数,参数个数由格式串中的格式控制符决定
  • 返回值

    • 成功:字符个数
    • 失败:负数

snprintf

  • 功能

  • 原型

    •   #include <stdio.h>
        int snprintf(char *str, size_t size, const char *format, ...);
      
  • 参数

    • char *str:字符数组容器
    • size_t size:容器大小
    • const char *format:格式串
    • ...:可变参数,参数个数由格式串中的格式控制符决定
  • 返回值

    • 成功:字符个数
    • 失败:负数

时间相关的函数

time

  • 功能:获取1970-1-1至今的秒数

  • 原型

    •   #include <time.h>
        time_t time(time_t *tloc);
      
  • 参数:

    • time_t *tloc:该指针指向的内存空间中,会存储获取到的秒数,也可以写NULL,代表参数中不存储秒数
  • 返回值:

    • 成功:返回获取到的秒数
    • 失败:返回-1,更新errno

localtime

  • 功能:将1970-1-1至今的秒数转换成日历格式

  • 原型:

    •   #include <time.h>
        struct tm *localtime(const time_t *timep);
      
  • 参数:

    • time_t *timep:指定要转换成日历格式的秒数
  • 返回值:

    • 成功:返回结构体指针
    • 失败:返回NULL,更新errno;
//vi -t tm
struct tm { 
	int tm_sec;    /* Seconds (0-60) */int tm_min;    /* Minutes (0-59) */int tm_hour;   /* Hours (0-23) */int tm_mday;   /* Day of the month (1-31) */int tm_mon;    /* Month (0-11) */=tm_mon+1 
    int tm_year;   /* Year - 1900 */=tm_year+1900 
    int tm_wday;   /* Day of the week (0-6, Sunday = 0) */    星期 
    int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */   一年的第几天
    int tm_isdst;  /* Daylight saving time */ 
           }; 

缓冲区

全缓冲

  • 操作对象:手动用fopen打开文件后,获取到的缓冲区均为全缓冲

  • 大小:4096byte = 4k

    fputc('a', fp);//先往缓冲区中存放一个字符'a'
    printf("%ld\n",fp->_IO_buf_end - fp_>_IO_buf_base);
    
  • 刷新缓冲区机制

    • 缓冲区满
    • 用fflush函数强制刷新
    #include <stdio.h>
    int fflush(FILE *stream);
    
    • 关闭流指针fclose(fp)

    • 主函数调用return

    • 调用exit退出程序

      • 无论在程序什么位置调用exit(),都会导致整个程序退出

      •   #include <stdio.h>
          void exit(int status);
        
      • 参数:

        • int status:整型参数

行缓冲

  • 操作对象:

    • 标准输入流指针FILE *stdin
    • 标准输出流指针FILE *stdout
  • 大小:1024bytes = 1k

  •   int num;
      scanf("%d", &num);
      printf("%ld\n", stdin->_IO_buf_end - stdin->_IO_buf_base);
    
  • 刷新缓冲区的机制

    • 缓冲区满

    • 用fflush函数强制刷新

    •   #include <stdio.h>
        int fflush(FILE *stream);
      
    • 关闭流指针fclose(stdout);基本不使用

    • 主函数调用return

    • 调用exit退出程序

无缓冲

  • 操作对象:标准错误输出流指针FILE *stderr
  • 大小:0
  • peror函数默认调用的就是stderr流指针

一般用于打印错误信息,防止错误信息在缓冲区中没有刷新,直接被销毁。

实时性比stdout高,但是效率会比stdout

概念

  • 文件IO是没有缓冲区的,只有标准IO有缓冲区
  • 文件IO函数是由操作系统提供的,与操作系统绑定,又称之为系统调用
  • 文件IO函数是通过文件描述符来维护一个文件

文件描述符

  • 当我们要去操作一个文件的时候首先要打开一个文件。尝试打开一个文件的时候,系统会自动给这个文件分配一个编号,这个编号就是文件描述符,用文件描述符来维护描述这个文件

  • 标准IO是对文件IO的二次封装,最终标准IO依然会去调用文件IO,所以FILE结构体中会有文件描述符成员_fileno

    • 在文件IO的基础上,封装了一个缓冲区,同时将文件描述符也一起封装到了FILE结构体中
  • 文件描述符的本质

    • 文件描述符的本质是数组下标,该数组的容量默认为1024,范围是[0,1023]

    • 文件描述符是有上限的,所以在不使用的情况下,需要关闭

    • 获取文件描述符的规则是,从小向大,依次获取,直到找到一个没有被使用的元素,返回该元素的下标。

    • 其中有三个特殊的文件描述符,分别为0,1,2

      特殊的流指针(FILE*)特殊文件描述符结构体位置
      FILE *stdin0stdin->_fileno
      FILE *stdout1stdout->_fileno
      FILE *stderr2stderr->_fileno
  • getdtablesize(void)获取一个进程最多能打开几个文件描述符

文件IO函数

open

  • 功能:打开一个文件

  • 原型:

    •   #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        
        int open(const char *pathname, int flags, ...);
        int open(const char *pathname, int flags);
        int open(const char *pathname, int flags, mode_t mode);
      
  • 参数:

    • char *pathname:指定要打开的文件路径以及名字

    • int flags:打开方式

      • 参数功能
        O_RDONLY只读
        O_WRONLY只写
        O_RDWR读写
      • 以上三种,必须且只能包含一个

        参数功能
        O_APPEND追加的方式
        O_CREAT如果文件不存在则创建
        O_TRUNC如果文件存在,则清空
      • 如果需要多个选项,可以用按位或连接

    • mode_t mode:在文件创建时,指定文件的权限使用

      ​ 当flags中指定了O_CREAT或者O_TMPFILE的时候,mode参数必须填写

      ​ 当flags没有指定上述两种选项,则mode参数会被忽略

  • 返回值:

    • 成功:返回新的文件描述符
    • 失败:返回-1,更新errno
  • fopen的打开方式,在open中组合

    • fopenopen
      rO_RDONLY
      wO_WRONLY |O_CREAT|O_TRUNC
      aO_WRONLY|O_CREAT|O_APPEND
      r+O_RDWR
      w+O_RDWR|O_CREAT|O_TRUNC
      a+O_RDWR|O_CREAT|O_ARREND

close

  • 功能:关闭文件,释放文件描述符对应的该空间

  • 原型

    •   #include <unistd.h>
        int close(int fd);
      
  • 参数:

    • int fd:指定要关闭的文件
  • 返回值:

    • 成功:0
    • 失败:-1,更新errno

write

  • 功能:将数据写入文件中

  • 原型:

    •   #include <unistd.h>
        ssize_t write(int fd, const void *buf, size_t count);
      
  • 参数

    • int fd:指定要写入哪个文件中,填对应的文件描述符
    • void *buf:指定要输出的数据首地址,可以输出任意类型的数据
    • size_t count:指定要输出的数据大小,以字节为单位
  • 返回值:

    • 成功:返回成功输出的字节数
    • 失败:返回-1,更新errno

read

  • 功能:从指定的文件中读取数据

  • 原型:

    •   #include <unistd.h>
        ssize_t read(int fd, void *buf, size_t count);
      
  • 参数

    • int fd:指定要读取哪个文件,填对应的文件描述符
    • void *buf:存储读取到的数据
    • size_t count:指定要读取多少个字节
  • 返回值

    • >0:成功,返回成功读取到的字节数
    • =0:读取到文件结尾
    • -1:失败,返回-1,更新errno
  • read不会自动补充\0字符

  • read函数遇到\n不会停止读取

lseek

  • 功能:修改文件偏移量

  • 原型:

    •   #include <sys/types.h>
        #include <unistd.h>
        off_t lseek(int fd, off_t offset, int whence);
      
  • 参数:

    • int fd:指定要修改哪个文件偏移量,填上对应的文件描述符
    • off_t offset:偏移量,新的位置为whence加上offset参数
      • 往结尾偏移,填正数
      • 往开头偏移,填负数
    • int whence
      • SEEK_SET,文件开头位置
      • SEEK_CUR,文件当前位置
      • SEEK_END,文件结尾位置
  • 返回值

    • 成功:返回文件偏移后的当前位置,距离文件开头的偏移量
    • 失败,返回(off_t)-1,更新errno
  • lseek(fd, 0, SEEK_END);,返回值为文件的大小

将系统时间以 年-月-日 时:分:秒 的格式一秒一次的写入指定文件中并记录行数

int get_fileline(FILE *fp_r)
{
	int line = 0;
	char buf[32] = " ";
	while(fgets(buf, sizeof(buf), fp_r) != NULL)
	{
		if(buf[strlen(buf)-1] == '\n')
		{
			line++;
		}
	}

	return line;

}

void time_to_file(FILE *fp_w)
{
	//定义一个接收系统时间的变量
	time_t t;
	//每次执行程序都能获取文件行数
	int line = get_fileline(fp_w);
	//定义一个localtime结构体指针
	struct tm* info = NULL;
	while(1)
	{

		//获取系统时间
		t = time(NULL);
		info = localtime(&t);

		//写入文件
		fprintf(fp_w, "[%d] %d-%02d-%02d %02d:%02d:%02d\n",\
				++line,\
				info->tm_year+1900,\
				info->tm_mon+1,\
				info->tm_mday,\
				info->tm_hour,\
				info->tm_min,\
				info->tm_sec);

		//刷新缓存区
		fflush(fp_w);
		//休眠一秒后再写入
		sleep(1);
	}
}

使用fread和fwrite实现文件拷贝功能

void copy_file(FILE* f_r, FILE* f_w)
{

	//分次读写,一次32字节
	char buf[32] = "";
	size_t res = 0;

	while(1)
	{
		//每次读一个字节,每次读sizeof(buf)-1,留一个位置给'\0'
		if((res = fread(buf, 1, sizeof(buf)-1, f_r)) == 0)
			break;
			//字符串结尾补0
		buf[res] = 0;
		fwrite(buf, 1, res, f_w);
	}
	puts("copy complete");

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值