C基础文件操作

Posted mChenys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C基础文件操作相关的知识,希望对你有一定的参考价值。

目录

一、文件的打开和关闭

1.1 fopen函数

FILE *fopen(const char*path,const char*mode);

fopen打开文件成功则返回有效的FILE地址,失败则返回NULL
path就是指定打开文件的路径,可以是相对路径,也可以是绝对路径.

模式(mode)有以下几种:

  • r:以只读的方式打开文件,该文件必须存在,且需要读的权限;
  • rb:读写方式打开一个二进制文件,文件必须存在且需要读的权限,b选项在windows有效,windows所有文本都是\\r\\n结尾的,而不是\\n结尾的,如果读文件的时候没有带b,那么系统会自动把\\r吃掉;
  • r+: 和r类似,只是它还可以写文件(前提是文件必须存在);
  • w:打开只写文件,如果文件存在则文件长度清0,即该文件内容会消失,若文件不存在则建立文件,需要写的权限,在windows上会自动在\\n前补齐\\r;
  • w+:和w类似, 只是它还可以读文件;
  • wb:在Windows下有效,它可以避免系统自动在\\n前添加\\r字符;
  • a:以追加的形式打开只写文件,若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留),需要写的权限;
  • a+:和a类似,同时可以读和写

其中b选项是二进制的意思,可以和上面的所有模式组合使用。

注意:在windows上读写一个二级制文件,一般要加b,防止系统添加无畏的\\r;但如果读写的是一个文本文件,那么不要加b,这样可以不用单独处理这个\\r.
在Windows系统中,文本模式下,文件以"\\r\\n"代表换行,若以文本模式打开文件,并用fputs等函数写入换行符"\\n"时,函数会自动在"\\n"前面追加"\\r".即实际写入文件的是"\\r\\n".
在类unix/linux系统的文本模式下,文件是以"\\n"代表换行的,所以linux系统的文本模式和二进制模式没有区别.

1.2 fclose函数

关闭打开的文件 ,和fopen配套使用,只要fopen成功返回,那就需要调用fclose释放资源。

fclose(FILE *stream);

二、读取和写入字符

2.1 getc/fgetc函数

读取字符

int getc(FILE *stream);

getc的参数是一个fopen成功打开的文件后返回的指针,getc返回的是一个char, 它的功能是以字节位单位读取文件内容, 文本文件的最后结束标记是-1,也就是一个EOF宏定义 #define EOF -1

#include <stdio.h>

int main()

    FILE *fp = fopen("user.txt", "r");
    char c;
    while ((c = getc(fp)) != EOF) //读取文件的每一个字符,直到末尾
    
        printf("%c", c);
    
    fclose(fp);
    return 0;


2.2 putc/fputc函数

输出字符

int putc(int c,FILE *stream);

参数1是要写入的char,参数2是fopen返回的文件指针。

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

int main()

    FILE *fp = fopen("a.txt", "w");
    const char *s = "hello world";
    int i;
    for (i = 0; i < strlen(s); i++)
    
        putc(s[i], fp); //向文件写入数据
    
    putc('\\n', fp); //添加换行符
    fclose(fp);
    return 0;


C语言中fgetc、fputc和getc、putc的区别是什么?

千万不要认为fgetc、fputc的f代表的是file,就是这两个函数是和文件有关的!得看看他们的函数声明,如下图:
看到没,参数都是可以接收FILE指针的,其实那个f代表的其实是function。

fgetc和getc他们的区别并不是在他们的使用上,而是在他们的实现上!具体来说,就是带f的(fgetc、fputc)实现的时候是通过函数来实现的,而不带f(putc、getc)的,实现的时候是通过宏定义来实现的!关于他们的不同点,就拿getc和fgetc来说:

  1. getc的参数不应当是具有副作用的表达式。
  2. 因为fgetc一定是一个函数,所以可以得到其地址。这就允许将fgetc的地址作为一个参数传送给另一个函数。
  3. 调用fgetc所需时间很可能长于调用getc,因为调用函数通常所需的时间长于调用宏。

2.3 案例-实现控制台输入文件名创建文件并支持写入功能

效果图如下:

打开目标文件

上代码:

#include <stdio.h>

int main(int argc, char **args)

    if (argc < 2)
        return 0;
    FILE *fp = fopen(args[1], "w");
    if (fp)
    
        while (1)
        
            printf("循环开始--\\n");
            char c = getchar(); //从标准控制台中每次读取一个char,包括回车符
            printf("收到%c\\n", c);
            if (c == '0')
                break;
            putc(c, fp);
            printf("--循环结束\\n");
        
        fclose(fp);
    
    return 0;


2.4 案例-实现控制台输入文件名读取该文件的内容

效果图如下:

#include <stdio.h>

int main(int argc, char **args)

    if (argc < 2)
        return 0;

    FILE *fp = fopen(args[1], "r"); //根据用户输入的路径读取
    if (fp)
    
        char c;
        while ((c = getc(fp)) != EOF)
        
            printf("%c", c);
        
        fclose(fp);
    
    return 0;

2.5 案例-实现echo的功能

效果图:

查看a.txt文件内容如下:

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

int main(int argc,char **args)

	if(argc <2)
		return 0;
	char *s = args[1]; //字符串内容
	char *op = args[2]; // > or >> ,注意控制台输入需要转义, \\> 或者 \\>\\>
	FILE *fp = NULL;
	if(strcmp(">",op)==0)
		fp = fopen(args[3],"w");  //新建
	if(strcmp(">>",op)==0)
		fp = fopen(args[3],"a");  //追加
	if(fp)
	
		int i;
		for(i = 0;i<strlen(s);i++)
		
			putc(s[i],fp);
		
		putc('\\n',fp);//末尾添加换行
		fclose(fp);
	

	return 0;

或者

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

    if (argc != 4)
    
        printf("Usage: test \\"hello\\" > a.txt");
        return -1;
    
    char *content = args[1];
    char *op = args[2];
    char *path = args[3];
    FILE *f = NULL;
    if (strcmp(op, ">") == 0)
    
        f = fopen(path, "w");
    
    else if (strcmp(op, ">>") == 0)
    
        f = fopen(path, "a");
    
    else
    
        printf("Unknow option:%s\\n", op);
        return -1;
    
    if (f)
    
        int size = strlen(content);
        for (int i = 0; i <= size; i++) // 注意:这里包含了size,这样字符串末尾的'\\0'也能输出
        
            putc(content[i], f);
        
        //putc('\\n',f);//末尾添加换行
        fclose(f);
    
    return 0;

2.6 案例-实现文件拷贝的命令

#include<stdio.h>

int main(int argc, char **args)

    if (argc != 3)
    
        printf("Usage:test a.txt b.txt");
        return -1;
    
    FILE *src = fopen(args[1], "r");
    FILE *dst = fopen(args[2], "w");
    if (src && dst)
    
        char c;
        while ((c = getc(src)) != EOF)
        
            putc(c, dst);
        
        fclose(src);
        fclose(dst);
    
    return 0;

2.7 实现文件加解密

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

int main(int argc, char **args)

    if (argc != 4)
    
        printf("Usage: pwd a.txt b.txt 0\\n0:加密\\n1:解密\\n");
        return -1;
    
    FILE *src = fopen(args[1], "r");
    FILE *dst = fopen(args[2], "a");
    char *op = args[3]; // 这里也可以使用args[3][0]取字符来对比
    if (src && dst)
    
        char c;
        while ((c = getc(src)) != EOF)
        
            if (strcmp(op, "0") == 0)
            
                // 加密
                c++;
            
            else if (strcmp(op, "1") == 0)
            
                // 解密
                c--;
            
            putc(c, dst);
        
        fclose(src);
        fclose(dst);
    
    return 0;

2.8 EOF与feof函数文件结尾

程序怎么才知道是否已经到达文件末尾了呢?EOF代表文件结尾,如果已经是文件的末尾,那么feof函数返回true,而EOF的值就是-1,在读文本文件的时候可以判断读到的字符是否是EOF或者调用feof返回true则表示读到文件的末尾了, 但是判断二进制文件则必须使用feof函数来判断. 因为字符的ASCII码不可能是EOF(-1), 但是二进制文件都是二进制数是可能出现-1的,所以二进制文件只能使用feof函数来判断。

int feof(FILE *stream);  

feof函数的滞后性
feof函数每次都是判断FILE里面的一个标记,只有当执行fgets、getc、fread函数的时候才会更新FILE内的标记,所以feof函数有滞后性。也就是说在fgets、getc、fread函数前调用feof的结果是上一次的结果。
下面看一个错误的示例

#include <stdio.h>

int main()

    FILE *fp = fopen("a.txt", "r");
    if (fp)
    
        char ch;
        while (!feof(fp)) //feof函数需要在fgetc调用后才是最新的,所以当fgetc读到末尾的时候,此时feof判断还是上次的状态,也就是没有到末尾,这样就会多循环一次
        
            ch = fgetc(fp);//当多循环一次的时候就会把EOF结束符也读取了.这样输出的结果就有问题了.
            printf("%c", ch);
        
        fclose(fp);
        fp = NULL;
    
    else
    
        printf("打开文件失败");
    
    return 0;


从输出结果可以看到多输出了一个字符.
正确的方式是这样的

#include <stdio.h>

int main()

    FILE *fp = fopen("a.txt", "r");
    if (fp)
    
        char ch;
        while (1)
        
            ch = fgetc(fp);
            if (feof(fp)) //改成在这里判断
                break;
            printf("%c", ch);
        
        fclose(fp);
        fp = NULL;
    
    else
    
        printf("打开文件失败");
    
    return 0;


或者这样

#include <stdio.h>

int main()

    FILE *fp = fopen("a.txt", "r");
    if (fp)
    
        char ch;
        while ((ch = fgetc(fp)) != EOF)
        
            printf("%c", ch);
        
        fclose(fp);
        fp = NULL;
    
    else
    
        printf("打开文件失败");
    
    return 0;

三、读取和写入一行文本

3.1 fprintf和fscanf函数

这2函数都是通过FILE *来对文本文件(字符)进行行的读写(每次都是操作数据),但不能用于操作二进制的文件(可执行程序,音乐等)。

int fscanf(FILE *stream, const char *format, ...); // 和sscanf功能一样,不同点是从文件中取解析
int fprintf(FILE *stream, const char *format, ...);// 和sprintf功能一样,不同点是向文件中输出

3.2 案例-将用户控制台输入的内容打印到文件中

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

int main()

	FILE *wf = fopen("a.txt","w");
	char buf[1024] = 0;
	while(1)
	
		scanf("%s",buf);
		if(strcmp("exit",buf) ==0)
			break;
		fprintf(wf,"%s\\n",buf);//按指定格式输出到文件中
	
	fclose(wf);
	return 0;

3.3 fgets和fputs函数

这2个函数可以配套使用,一次读写一个字符串内容.

char *fgets(char *s, int size, FILE *stream); //每次读取一行字符串,包括换行符
int fputs(const char *s, FILE *stream); //每次输出一行字符串

下面实现从控制台输入内容到文件中保存

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

int main(int argc, char **args)

    if (argc < 2)
        return 0;
    FILE *wf = fopen(args[1], "w");
    while (1)
    
        char buf[1024] = 0;
        fgets(buf, sizeof(buf), stdin); //从控制台读取数据到buf中,注意fgets还可以从文件中读取,第三个参数改成FILE *即可
        if (strncmp(buf, "exit", 4) == 0)
            break;

        fputs(buf, wf); //写到文件中
    
    fclose(wf);

    return 0;

3.4 案例-实现文件拷贝

#include<stdio.h>

int main(int argc,char **args)
C基础文件操作

关于C语言读取文件结尾的问题

C基础文件操作

算法基础-冒泡排序

C 语言文件操作 ( 文件结尾判定 )

fread()函数如何判断是不是到文件末尾?