C语言-输入输出

  • 流(Stream): C语言中,流表示==任意输入的源或任意输出的目的地==。
  • 流经常表示存储在不同介质的==文件==,也经常和==不存储文件的设备(如网络端口,打印机)==关联。
  • <stido.h>中的函数可以处理各种形式的流。

文件指针

  • 文件指针(file pointer):C程序中==对流的访问是通过文件指针来实现的==。
  • 文件指针的类型FILE *
    • FILE类型是在<stdio.h>中声明的。
    • 示例:FILE *fp1;

标准流和重定向

  • <stdio.h>提供了3个标准流:
    1. stdin:标准输入流,默认是键盘。
    2. stdout:标准输出流,默认是屏幕。
    3. stderr:标准错误,默认是屏幕。
  • 标准流的特性
    • 这三个标准流==可以直接使用,不需要对其进行声明,也不用打开或者关闭==。
    • stdin,stdout,stderr是三个==文件指针==。
  • 重定向
    • 操作系统通过==重定向的操作改变标准流的默认含义==。
    • 输出重定向:使stdin流表示文件,而不是键盘,通过在命令行中使用<实现,如:demo <in.dat,运行demo程序时从in.dat文件中获取数据。
    • 输出重定向:使stdout流表示文件,而不是屏幕,通过在命令行中使用>实现,如:demo >out.dat,运行demo程序时输出到out.dat文件中。

文本文件和二进制文件

  • <stdio.h>支持文本文件二进制文件
  • 文本文件(text file)
    • 在文本文件中,==字节表示字符==;
    • 文本文件分为若干行
      • 文本文件的每一行通常==以一两个特殊字符结尾==;
      • windows系统是以==回车符\x0d和回行符\x0a==结尾;
      • unix操作系统是以==一个单独的回行符\x0a==结尾。
    • 文本文件末尾可以包含一个特殊的文件末尾标识符
      • 文件末尾标识==不是必须的,但一旦存在,就标志着文件的结束==。
  • 二进制文件
    • 在二进制文件中,==字节可以表示很多类型的数据==。
    • 二进制文件==不分行,没有行末标记和文件末尾标记==。

文件操作

  • <stdio.h>提供了一系列的文件操作,包括打开文件,关闭文件,改变文件的缓冲方式,删除文件以及重命名文件等。

打开文件

  • fopen()函数
    • 将文件打开并用作==流==;
    • 原型:FILE *fopen(const char *filename, const char *mode)
    • filename:要打开文件的文件名(可能包含文件的==路径信息==。)
      • 路径:在windows系统中的路径中含有\,会被C语言识别为转移字符,而导致错误。常用\\或者/来替换路径中的\
    • mode:==模式字符串==,用来指定打算对文件执行的操作。对==文本文件和对二进制文件的模式字符串是不一样的==。
      • 文本文件的六种模式字符串:
        1. "r":打开文件用于读;
        2. "w":打开文件用于写(文件不需要存在)
        3. "a":打开文件用于追加(文件不需要存在)
        4. "r+"":打开文件用于==读和写,从文件头开始==;
        5. "w+":打开文件用于==读和写(如果文件存在就清空)==;
        6. "a+":打开文件用于==读和写(如果文件存在就追加)==。
      • 二进制文件也有六种模式字符串,只需要在文件文件的基础上==加上b==即可。
    • 返回值
      • fopen函数的返回值是一个==文件指针==;
      • 当无法代开文件时,会==返回一个空指针==。

关闭文件

  • flclose()函数:
    • 关闭不再使用的文件。
    • 原型:int fclose(FILE *stream)
    • 参数
      • ==必须是来自fopen函数或者freopen函数的文件指针==;
    • 返回值
      • 如果成功关闭的文件,返回==0==;
      • 如果失败,返回==EOF==(EOP是<stdio.h>中定义的宏)

为打开的流附加文件

  • freopen()函数
    • 该函数为已经打开的流附加上一个不同的文件。
    • 原型:FILE *freopen(const char *filename, const char *mode, FILE *stream)
    • 参数:
      • 前两个参数同fopen一样;
      • 第三个参数是一个文件指针,指向一个已经打开了的流。
    • 返回值
      • 正常的返回值是它的第三个参数,一个文件指针;
      • 如果无法打开新文件,返回==空指针==。

从命令行获取文件名

  • 执行程序时,可以通过将==文件名放入命令行的方式为程序提供文件名==。
  • 示例:命令demo demo1.txt demo2.txt,其中demo是程序名,剩下的是文件名。在C语言中argv[1]指向字符串demo1.txt,argv[2]指向字符串demo2.txt

临时文件

  • 临时文件:==只在程序运行时==存在的文件。
  • <stdio.h>提供了两个函数来处理临时文件。
  • tmpfile():
    • tmpfile函数用于==创建临时文件==(用wb+模式打开),这个临时文件在==关闭它或者程序终止==时消失。
    • 原型:FILE *tmpfile(void)
    • 返回值:
      • 如果创建文件成功,会返回==文件指针==;
      • 如果创建失败,返回==空指针==。
    • 特点:
      • 无法知道tmpfile创建的临时文件的==文件名==;
      • 无法使用tmpfile创建的文件成为==永久性的==。
  • tmpnam():
    • tmpname函数为临时文件==产生名字==。
    • 原型:char *tmpnam(char *s);
    • 参数:
      • 如果参数是一个空指针,tmpnam会==将生成的文件名存储到一个静态字符数组变量中去,并且返回指向这个变量的指针==;
      • 传递给tmpnam的参数应该是一个==字符数组==,tmpnam会将文件名存储到这个字符数组中去,并==返回指向这个数组第一个元素的指针==。
    • tmpnam函数常与fopen函数配合生成具有名字的临时文件。

文件缓冲

  • 使用文件缓冲的原因:向外存写入或者读出数据都是==相对较慢==的操作。
  • 缓冲(buffering):将写入流或者输入流中的数据,先写入==缓冲区==,最后再将缓冲区的内容写入实际的设备。
  • <stdio.h>中的缓冲函数,会在缓冲有用时==自动进行缓冲操作==,缓冲是在后台发生的。
  • fflush函数
    • 调用fflush函数,可以按照我们希望的频率==将缓冲区的内容写到相应设备上去==。
    • 原型:int fflush(FILE *stream)
    • 参数:
      • 如果传递的是一个==文件指针==,则将与该文件指针相关联的文件的缓冲区内容写到实际设备。
      • 如果传递的是一个==空指针==,则将所有缓冲区内容写到实际设备上去。
    • 返回值;
      • 调用成功,==返回0==;
      • 调用失败,==返回EOF==。
  • setvbuf函数:
    • 改变缓冲流的方法,并且允许控制缓冲区的大小和位置。
    • 原型:int setvbuf(FILE *stream, char *buf, int mode, size_t size);
    • 参数:
      • stream:需要改变缓冲方式的流;
      • buf:期望的==缓冲区的地址==;
        • 如果实参为空指针,则会==创建一个指定大小的缓冲区==。
      • mode:期望的缓冲类型,只能为==下列三个宏==:
        1. _IOFBF:==满缓冲==,当缓冲区为空时,从流读入数据;当缓冲区满时,向流写入数据;
        2. _IOLBF:==行缓冲==,每次从流读入一行数据或者向流写入一行数据;
        3. _IONBF:==无缓冲==,直接从流读入数据或者直接向流写入数据,而没有缓冲区。
      • size:缓冲区内==字节的数量==。
    • 返回值:
      • 调用成功,==返回0==;
      • 调用失败,==返回非零值==。
  • setbuf函数:
    • setvbuf的早期版。

文件删除与重命名

  • remove函数
    • 用于删除文件;
    • 原型:int remove(const char *filename)
    • 参数:
      • 文件名
    • 返回值:
      • 成功,0;
      • 失败,非零值。
    • 要删除的文件需要关闭
  • rename函数
    • 改变文件的名字;
    • 原型:int rename(const char *old, const char *new)
    • 参数:
      • old:原来的文件名;
      • new:新的文件名。
    • 返回值:
      • 成功,0;
      • 失败,非零值。
    • 注意:
      • 要改名的文件需要关闭