c语言IO函数

1.fgets、fputs文件操作,文件加密, 逐行读写

1) 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
r(read): 读
w(write): 写
a(append): 追加
t(text): 文本文件,可省略不写
b(banary): 二进制文件
rb+:可读可写
+: 读和写
2) 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
3) 用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。
4) a  打开只写文件,如果文件不存在,建立文件, 写入追加
5) 在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理
 
  r windows下文本文件,\r\n代表换行,使用fputss函数写入\n,函数自动会在\n前面加\r,读出来以后只有\n,自动去掉\r
  rb二进制来读文本文件,那么不会对\r\n进行省略
  unix\linux文本文件中,\n表示换行
  
\r: ascII  d   13
\n:        a   10
 

 代码:

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


// 输入内容写文件
int main01(void)//写文件
{
    char s[1024] = { 0 };
    FILE *p = fopen("D:\\temp\\a.txt", "w");//用写的方式打开一个文件
    //"w"意思就是如果文件不存在,就建立一个人间,如果文件存在就覆盖
    while(1)
    {
        memset(s, 0, sizeof(s));
        //scanf("%s", s); 
		//scanf和 gets的区别:scanf如果 判断输入空格,那么会换行,gets可以接收空格
        gets(s);
        if (strcmp(s, "exit") == 0)
            break;//如果用户输入的是exit,那么循环退出
        int len = strlen(s);
        s[len] = '\n';
        fputs(s, p);
    }
    fclose(p);//关闭这个文件
    //操作一个文件的步骤和把大象放冰箱是一样的
    printf("end\n");
    return 0;
}
 // 逐行读取内容
int main02()
{
    char s[1024] = { 0 };
    FILE *p = fopen("D:\\temp\\main.c", "r");//用读的方式打开一个文件
    //feof(p);//如果已经到了文件结尾,函数返回真
    while(!feof(p))//如果没有到文件结尾,那么就一直循环,如果是文件末尾,返回0
    {
        memset(s, 0, sizeof(s));
        fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
        printf("%s", s);
    }
    fclose(p);
    return 0;
}

void code(char *s)
{
    while(*s)//遍历一个字符串
    {
        (*s)++;  // 文件的 加密,为每一个字符串都加1
        s++;
    }
}

void decode(char *s)
{
    while(*s)//遍历一个字符串
    {
        (*s)--;
        s++;
    }
}
// 这里实现文件的加密功能
int main03()
{
    char s[1024] = { 0 };
    FILE *p = fopen("D:\\temp\\a.txt", "r");//用读的方式打开一个文件
    FILE *p1 = fopen("D:\\temp\\b.txt", "w");//用写的方式打开一个文件
    //feof(p);//如果已经到了文件结尾,函数返回真
    while(!feof(p))//如果没有到文件结尾,那么就一直循环
    {
        memset(s, 0, sizeof(s));
        fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
        code(s);//
        fputs(s, p1);
    }
    fclose(p);
    fclose(p1);
    return 0;
}
// 这里 实现对加密 后的 文件  进行解密 功能 解密功能
int main()
{
    char s[1024] = { 0 };
    FILE *p = fopen("D:\\temp\\b.txt", "r");//用读的方式打开一个文件
    FILE *p1 = fopen("D:\\temp\\c.txt", "w");//用写的方式打开一个文件
    //feof(p);//如果已经到了文件结尾,函数返回真
    while(!feof(p))//如果没有到文件结尾,那么就一直循环
    {
        memset(s, 0, sizeof(s));
        fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
        decode(s);//
        fputs(s, p1);
    }
    fclose(p);
    fclose(p1);
    return 0;
}



2.getc、putc,  逐字节读写

#include <stdio.h>

int main01(void)
{
    FILE *p = fopen("D:\\temp\\a.txt", "r");
    if (p == NULL)
    {
        printf("error\n");
    }else
    {

        char c = 0;
        while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示
		// -1 表示文件的结尾
		// EOF就是-1,一个宏
        {
            //c = getc(p);//一次只读取一个字符
            printf("%c", c);
        }
        fclose(p);
    }
    return 0;
}

int main02(void)//写一个字符
{
    FILE *p = fopen("D:\\temp\\a.txt", "w");
    if (p == NULL)
    {
        printf("error\n");
    }else
    {
        putc('a', p);
        putc('b', p);
        putc('c', p);
        fclose(p);
    }
    return 0;
}

#define SEC 5

int main03(void)//加密
{
    FILE *p = fopen("D:\\temp\\a.txt", "r");
    FILE *p1 = fopen("D:\\temp\\b.txt", "w");
    if (p == NULL)
    {
        printf("error\n");
    }else
    {

        char c = 0;
        while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示,系统api
        {
            c += SEC;
            putc(c, p1);
        }
        fclose(p);
        fclose(p1);
    }
    return 0;
}

int main(void)//解密
{
    FILE *p = fopen("D:\\temp\\b.txt", "r");
    FILE *p1 = fopen("D:\\temp\\c.txt", "w");
    if (p == NULL)
    {
        printf("error\n");
    }else
    {

        char c = 0;
        while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示
        {
            c -= SEC;
            putc(c, p1);
        }
        fclose(p);
        fclose(p1);
    }
    return 0;
}


3.bin-file: 二进制文件操作

二进制文件加密
   fread
   fwrite
 fread指定读取字节数,
 如果一次读取内容越大,拷贝花费时间越少,占用内存大
  // 每一个文件用UltraEdit 打开都有固定的格式,特定的文件头,可以百度查一下文件格式

3.1.二进制API:

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

int main01(void)
{
    FILE *p = fopen("D:\\temp\\bin-file.exe", "rb");//用读二进制的方式打开一个文件
	// 加上b: window下是以\r\n结尾,不会丢失\r
	// 读的时候会把\r去掉, 写的时候会自动加上\r, 在window下
    //    char buf[1024] = { 0 };
	//    一次读sizeof(buf)个字节
    //    size_t res = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
	
    //    //fread返回值代表读取了多少记录数
    //    printf("res = %u\n", res);

    //    res = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
    //    //fread返回值代表读取了多少记录数
    //    printf("res = %u\n", res);
    while(!feof(p))  // 判断文件是否到头了
    {
        char buf[1024] = { 0 };
        int res  = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
        int i;
        for(i = 0; i < res; i++)
        {
            printf("buf[%d] = %x\n", i, buf[i]);
        }
    }
    fclose(p);
    return 0;
}

int main02()
{
    FILE *p = fopen("D:\\temp\\a.dat", "wb");
    //    char buf[1024] = { 0 };
    //    buf[0] = 'a';
    //    buf[1] = 'b';
    //    buf[2] = 'c';
    //    buf[3] = 'd';
    //    fwrite(buf, sizeof(char), sizeof(buf), p);

    int a = 0x12345678;
    fwrite(&a, 0, 4, p);
    fclose(p);
    return 0;
}

void code(char *p, size_t n)
{
    size_t i;
    for(i = 0; i < n; i++)
    {
        p[i] += 3;
    }
}

void decode(char *p, size_t n)
{
    size_t i;
    for(i = 0; i < n; i++)
    {
        p[i] -= 3;
    }
}

int main03()//二进制加密
{
    FILE *p = fopen("D:\\temp\\a.wmv", "rb");
    FILE *p1 = fopen("D:\\temp\\b.wmv", "wb");

    //    FILE *p = fopen("D:\\temp\\a.txt", "rb");
    //    FILE *p1 = fopen("D:\\temp\\b.txt", "wb");

    char buf[1024 * 4];//4k,每次读取4k字节
	//如果一次读取内容越大,拷贝花费时间越少,占用内存大
    while(!feof(p))
    {
        memset(buf, 0, sizeof(buf));
        size_t res = fread(buf, sizeof(char), sizeof(buf), p);//返回从源文件中读取的字节数
        code(buf, res);
        fwrite(buf, sizeof(char), res, p1);//从源文件中读取多少字节,那么就往目标文件中写入多少字节
    }
    fclose(p);
    fclose(p1);
    printf("end\n");
    return 0;

}

int main()//二进制解密
{
    clock_t c1 = clock();
    FILE *p = fopen("D:\\temp\\b.wmv", "rb");
    FILE *p1 = fopen("D:\\temp\\c.wmv", "wb");

    //    FILE *p = fopen("D:\\temp\\b.txt", "rb");
    //    FILE *p1 = fopen("D:\\temp\\c.txt", "wb");

    char buf[1024 * 4];
    while(!feof(p))
    {
        memset(buf, 0, sizeof(buf));
        size_t res = fread(buf, sizeof(char), sizeof(buf), p);//返回从源文件中读取的字节数

        //decode(buf, res);
        fwrite(buf, sizeof(char), res, p1);//从源文件中读取多少字节,那么就往目标文件中写入多少字节
    }
    fclose(p);
    fclose(p1);
    clock_t c2 = clock();
    printf("end , %u\n", c2 - c1);
    return 0;

}



3.2.fscanf: 从文件中输入    fprintf: 字节打印到文件

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

// 
int main01(void)
{
    FILE *p = fopen("D:\\temp\\a.txt", "r");
    while(!feof(p))
    {
        char buf[100] = { 0 };
        //fgets(buf, sizeof(buf), p);
        //fscanf(p, "%s", buf);//fscanf与scanf用法基本一致,fscanf是从一个文件读取输入,scanf是从键盘读取输入
        int a = 0;
        int b = 0;
        fscanf(p, "%d + %d =", &a, &b);
        printf("a = %d, b = %d\n", a, b);
        //printf("%s\n", buf);
    }
    fclose(p);
    return 0;
}

int main()
{
    FILE *p = fopen("D:\\temp\\a.txt", "w");
    int array[10] = {1,2,3,4,5,6,7,8,9,10};
    int i;
    for(i = 0; i < 10; i++)
    {
        fprintf(p, "array[%d] = %d\n", i, array[i]);
    }


//    char buf[100] = "hello world";
//    int a = 6;
//    int b = 7;
    //fprintf(p, "%s,%d, %d", buf, a, b);//和printf功能一样,fprintf将输入到文件里面
    fclose(p);
    return 0;
}

3.3.state大文件拷贝,获取文件属性

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>

int main(void)
{
    clock_t c1 = clock();//得到系统当前时间,单位:毫秒
    struct stat st = { 0 };//定义一个结构,名字叫st
    stat("D:\\temp\\a.wmv", &st);//调用完stat函数之后,文件相关的信息就保存在了st结构中了
    //st.st_size得到文件的大小
//    printf("%u\n", st.st_size);
//    printf("Hello World!\n");

    char *array = malloc(st.st_size);//根据文件大小在堆中动态的分配一块内存
    FILE *p = fopen("D:\\temp\\a.wmv", "rb");
    fread(array, sizeof(char), st.st_size, p);//相当于一下把整个文件放入了内存
    fclose(p);
    p = fopen("D:\\temp\\b.wmv", "wb");
    fwrite(array, sizeof(char), st.st_size, p);//将堆中的信息一下都写入文件
    fclose(p);
    clock_t c2 = clock();//得到系统当前时间,单位:毫秒

    printf("end, %u\n", c2 - c1);

    return 0;
}

3.4.struct-file: 二进制读写操作结构体

#include <stdio.h>

#include <string.h>

struct student
{
    char name[100];
    int age;
};

int main01(void)
{
	 // 把结构的内存地址写入磁盘中
    struct student st = {"刘德华", 30};
    FILE *p = fopen("D:\\temp\\a.dat", "wb");
    fwrite(&st, sizeof(st), 1, p);
    fclose(p);
    return 0;
}

int main(void)
{
    struct student st = {0};
    FILE *p = fopen("D:\\temp\\a.dat", "rb");
    fread(&st, sizeof(st), 1, p);
    fclose(p);
    printf("name = %s, age = %d\n", st.name, st.age);
    return 0;
}

读写基本数据类型:

  FILE* file = fopen("D:\\bb.txt", "wb");
	if (file == NULL){
		printf("文件打开失败");
	}
	else
	{
		int a = 5;
		fwrite(&a, sizeof(int), 1, file);
		fwrite(&a, sizeof(int), 1, file);
		fwrite(&a, sizeof(int), 1, file);
		fwrite(&a, sizeof(int), 1, file);
		fflush(file);
		fclose(file);
	}

	FILE* file = fopen("D:\\bb.txt", "rb");
	int a,b,c,d = 0;
	while (fread(&a, sizeof(int), 1, file)!=0)
	{
		printf("%s", "a");
		printf("%d\n", a);
	}

	fclose(file);

3.5.file-seek: seek 函数的使用

// 把 结构体 使用二进制 的方式读取出来,然后根据年龄使用冒泡 排序,然后打印出来

fseek的返回值为0表示成功,-1表示失败,
如果往后移动文件指针,超过文件大小,fseek返回0
如果往前移动文件指针,超过文件开始位置,返回-1
不能用于判断指针是否越界文件内容

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

struct student
{
    char name[10];
    int age;
};
  // 准备文件:把struct student st[5]这个 结构体做为5行保存到文件中
int main05(void)
{
    struct student st[5] = { 0 };
    int i;
    for(i = 0; i < 5; i++)
    {
        printf("please name:");
        scanf("%s", st[i].name);
        printf("please age:");
        scanf("%d", &st[i].age);
    }

    FILE *p = fopen("D:\\temp\\a.dat", "wb");
    fwrite(st, sizeof(struct student), 10, p);
    fclose(p);
    return 0;
}
 //
int main02()
{
    struct student st = { 0 };
    FILE *p = fopen("D:\\temp\\a.dat", "rb");

    //fseek(p, sizeof(struct student) * 2, SEEK_SET);//从文件开始位置向后偏移结构student这么多的字节

    memset(&st, 0, sizeof(struct student));
    fread(&st, sizeof(struct student), 1, p);
    printf("name = %s, age = %d\n", st.name, st.age);
     
    fseek(p, 0 - sizeof(struct student), SEEK_CUR);//从当前位置往回偏移,偏移一个结构,一共5个结构

    memset(&st, 0, sizeof(struct student));
    fread(&st, sizeof(struct student), 1, p);
    printf("name = %s, age = %d\n", st.name, st.age);

    fseek(p, 0 - sizeof(struct student), SEEK_END);//从文件结尾位置往回偏移, 一个结构

    memset(&st, 0, sizeof(struct student));
    fread(&st, sizeof(struct student), 1, p);
    printf("name = %s, age = %d\n", st.name, st.age);


    //    while(1)
    //    {
    //        memset(&st, 0, sizeof(struct student));
    //        if (fread(&st, sizeof(struct student), 1, p) == 0)
    //            break;
    //        printf("name = %s, age = %d\n", st.name, st.age);
    //    }
    fclose(p);
    return 0;

}

//a.txt 的内容是 abcdefj
int main03()
{
    FILE *p = fopen("D:\\temp\\a.txt", "rb");
     //abcdef, 偏移2个字节,那么只能读取cdef
    fseek(p, 2, SEEK_SET);
    char buf[100] = { 0 };
    fgets(buf, sizeof(buf), p); 
    printf("buf = %s\n", buf);
    fgets(buf, sizeof(buf), p);  
    printf("ftell = %d\n", ftell(p));   // ftell()是以字节为单位的,当前指针位置
    fclose(p);
    return 0;

}

int main04()
{
    FILE *p = fopen("D:\\temp\\a.txt", "rb");
    while(!feof(p))
    {
        fseek(p, 0, SEEK_END);//偏移到文件最后
        char buf[100] = { 0 };
        fgets(buf, sizeof(buf), p);
        printf("buf = %s", buf);
    }
    fclose(p);
    return 0;

}

void swap(struct student *a, struct student *b)
{
    struct student tmp = *a;
    *a = *b;
    *b = tmp;
}
  // 冒泡排序
void bubble(struct student *p, int n)
{
    int i;
    int j;
    for(i = 0; i < n; i++)
    {
        for(j = 1; j < n - i; j++)
        {
            if (p[j - 1].age > p[j].age)
            {
                swap(&p[j - 1], &p[j]);
            }
        }
    }
}

int main(void)
{
    struct student st[5] = { 0 };
    FILE *p = fopen("D:\\temp\\a.dat", "rb");
    int i;
//    for(i = 0; i < 5; i++)//读取文件的代码
//    {
//        fread(&st[i], sizeof(struct student), 1, p);
//    }
    fread(st, sizeof(struct student), 5, p);
    fclose(p);
     // 把 结构体 使用二进制 的方式读取出来,然后根据年龄使用冒泡 排序,然后打印出来
    bubble(st, 5);

//    for(i = 0; i < 5; i++)
//    {
//        printf("name = %s, age = %d\n", st[i].name, st[i].age);
//    }

    p = fopen("D:\\temp\\b.dat", "wb");
//    for(i = 0; i < 5; i++)
//    {
//        fwrite(&st[i], sizeof(struct student), 1, p);
//    }
    fwrite(st, sizeof(struct student), 5, p);
    fclose(p);

    return 0;
}

3.6练习:如果一个文件保存大量数据,排序那么读取到栈中首先,堆中可以存储不了,太大了

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

void swap(int *a, int *b)//交换参数的值
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void pupple(int *p, int n)//冒泡排序
{
    int i;
    int j;
    for(i = 0; i< n; i++)
    {
        for(j = 1; j < n - i; j++)
        {
            if (p[j - 1] > p[j])
            {
                swap(&p[j - 1], &p[j]);
            }
        }
    }
}

int main01(void)//在栈中建立一个数组对文件内容进行排序
{
    int index = 0;//这是个计数器
    int array[100] = { 0 };
    char buf[100];
    FILE *p = fopen("D:\\temp\\a.txt", "r");
    while(!feof(p))//如果没有到达文件结尾,那么循环继续
    {
        memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
        fgets(buf, sizeof(buf), p);//从文件中读取一行
        array[index] = atoi(buf);//将读取到的一行转化为int,赋值给数组成员
        index++;
    }
    fclose(p);
    pupple(array, index);//将数组排序
    p = fopen("D:\\temp\\b.txt", "w");//用写的方式打开b.txt
    int i;
    for(i = 0; i < index; i++)
    {
        memset(buf, 0, sizeof(buf));//每次操作之前都把buffer清空
        sprintf(buf, "%d\n", array[i]);//将数组的成员转化为字符串
        fputs(buf, p);
    }
    fclose(p);
    return 0;
}


int main(void)//在堆建立一个数组对文件内容进行排序
{
    int index = 0;//这是个计数器
    char buf[100];

    FILE *p = fopen("D:\\temp\\a.txt", "r");//第一次打开a.txt目的是要知道这个文件有多少行
    while(!feof(p))//如果没有到达文件结尾,那么循环继续,第一次循环的时候并不是要处理文件的内容,只是统计文件的行数
    {
        memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
        fgets(buf, sizeof(buf), p);//从文件中读取一行
        index++;
    }
    fclose(p);

    int *array = calloc(sizeof(int), index);//在堆中建立一个动态数组,动态数组的成员数量和a.txt文件的行一样多

    p = fopen("D:\\temp\\a.txt", "r");
    index = 0;//计数器从0重新开始
    while(!feof(p))//如果没有到达文件结尾,那么循环继续
    {
        memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
        fgets(buf, sizeof(buf), p);//从文件中读取一行
        array[index] = atoi(buf);//将读取到的一行转化为int,赋值给数组成员
        index++;
    }
    fclose(p);
    pupple(array, index);//将数组排序
    p = fopen("D:\\temp\\b.txt", "w");//用写的方式打开b.txt
    int i;
    for(i = 0; i < index; i++)
    {
        memset(buf, 0, sizeof(buf));//每次操作之前都把buffer清空
        sprintf(buf, "%d\n", array[i]);//将数组的成员转化为字符串
        fputs(buf, p);
    }
    fclose(p);
    return 0;
}

不用读取到堆中,使用快速排序,把数据做为数组角标索引

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

int main(void)
{
    srand((unsigned int)time(NULL));
    int i;
    FILE *p = fopen("D:\\temp\\a.txt", "w");
    for(i = 0; i < 100000; i++)
    {
        fprintf(p, "%d\n", (int)rand() % 513);
    }
    //文本文件,每行代表一个整数,整数是从0到512之间一个随机数
    //对这个文件进行排序,不能用堆内存,只能用栈内存
    fclose(p);

    p = fopen("D:\\temp\\a.txt", "r");
    int array[513] = { 0 };
    while (!feof(p))
    {
        char buf[100] = { 0 };
        fgets(buf, sizeof(buf), p);//得到一行
        if (buf[0] != 0)//如果读取的行不是空行,那么就执行代码
        {
            int value = atoi(buf);//将得到的行转化为int
            array[value]++;
        }
    }
    fclose(p);

    p = fopen("D:\\temp\\b.txt", "w");

    int j;
    for(i = 0; i < 513; i++)
    {
        for(j = 0; j < array[i]; j++)
        {
            fprintf(p, "%d\n", i);
        }
    }
    fclose(p);

    printf("end\n");

    return 0;
}

//int main(void)
//{

//    return 0;
//}

4. 文件的其他操作 file-fflush、remove、rename


 ** 如何明确调用fclose关闭一个文件,那么在进程退出以后,操作系统会自动调用fclose
  --不建议
 

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

int main01(void)
{
    FILE *p = fopen("D:\\temp\\a.txt", "w");
    while(1)
    {
        char buf[100] = { 0 };
        scanf("%s", buf);
        if (strcmp(buf, "exit") == 0)
            break;
        fprintf(p, "%s\n", buf);
        fflush(p);//fflush将缓冲区的内容立刻写入文件
        //优势是,不会因为停电,或者电脑死机等故障导致缓冲区的内容丢失
        //不好的,硬盘读写次数增加,导致程序效率低下,同时硬盘寿命变短
        //修改配置文件的时候,有时候会使用,或者做一些不经常修改的数据,但很重要数据,那么用fflush
    }
    fclose(p);  // 调用fclose 才把数据写入到 磁盘中去
    return 0;
}


int main()
{
    //remove("D:\\temp\\b.txt");//删除d:\temp\b.txt
    rename("D:\\temp\\c.txt", "D:\\temp\\a.txt");//将指定文件改名
    return 0;
}

发布了141 篇原创文章 · 获赞 51 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/104094105
今日推荐