09-标准文件

文件

文本文件 : 存储时,是将字符的ascii值存在磁盘中,取的时候将数值(ascii)翻译成对应的字符
二进制文件(例如图片): 存的是二进制,取的是二进制
![[Pasted image 20230831214854.png]]

文件指针

当打开一个文件时,系统会返回一个结构体,这个结构体有对此文件操作的所有信息
调用fopen时,系统返回这个结构体地址

![[Pasted image 20230831215352.png]]

打开文件

 FILE  *fp =  fopen( "pathname",  打开的方式  );

注意: 打开的选项
只有带r的选项,如果文件不存在,则不创建文件
带w选项的,打开时会清空文件
fopen的返回值: 如果成功返回FILE结构体地址,失败返回NULL
返回的文件流指针标识了打开的那个文件
![[Pasted image 20230831220802.png]]

	//r 只读 ,如果文件不存在,不创建
	//w 只写  清空文件 ,如果文件不存在,创建文件
	//r+ 可读可写  如果文件不存在,不创建
	//w+ 可读可写清空文件,  如果文件不存在,创建文件
	//a追加   如果文件不存在,会创建文件
	//b  二进制文件
	//打开一个文件,成功返回FILE结构体地址,失败返回NULL
	FILE *fp = fopen("./a.txt","w");
	if (NULL == fp)
	{
		   perror("open");
		   return;
	}

fputc

功能:写入一个字符到文件中

#include <stdio.h>
int fputc(int ch, FILE * stream);
/*
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
       ch:需要写入文件的字符
       stream:文件指针
返回值:
       成功:成功写入文件的字符
       失败:返回-1
*/
	FILE *fp = fopen("./a.txt","w");
	if (NULL == fp)
	{
		   perror("open");
		   return;
	}
	char buf[] = "hello";
	int i = 0;
	while (buf[i] != 0)
	{
		   fputc(buf[i],fp);
		   i++;
	}

fgetc

#include <stdio.h>
int fgetc(FILE * stream);
/*
功能:从stream指定的文件中读取一个字符
参数:
       stream:文件指针
返回值:
       成功:返回读取到的字符
       失败:-1
*/

feof

如果读取文件不是纯文本,有像-1这种数值,那么久不可以使用EOF(-1)作为文件的结尾。

#include <stdio.h>
int feof(FILE * stream);
/*
功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:
       stream:文件指针
返回值:
       非0值:已经到文件结尾
       0:没有到文件结尾
*/

fgets 从文件读取字符串

注意: fgets读取遇到\n结束

#include <stdio.h>
char * fgets(char * str, int size, FILE * stream);
/*
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
       str:字符串
       size:指定最大读取字符串的长度(size - 1)
       stream:文件指针
返回值:
       成功:成功读取的字符串
       读到文件尾或出错: NULL
*/

fputs 向文件写入字符串

#include <stdio.h>
int fputs(const char * str, FILE * stream);
/*
功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0'  不写入文件。
参数:
       str:字符串
       stream:文件指针
返回值:
       成功:0
       失败:-1
*/

文件拷贝案例

    // 打开src文件
    FILE *src = fopen("./a.txt", "r");
    if (!src) {
        perror("src open fail");
        return -1;
    }

    FILE *dest = fopen("./my_a.txt", "w");
    if (!dest) {
        perror("dest open fail");
        return -1;
    }

    char ch = 0;
    while (1)
    {
        // 读取src一个字符
        ch = fgetc(src);
        // 如果读到了文件末尾,就结束了
        if (feof(src))
            break;
        // 写入dest文件中
        fputc(ch,dest);

		// 打印到终端
        ch = fgetc(src);
        if (feof(src))
            break;
        // stdout是输出到显示器,程序运行时系统自动打开
        fputc(ch, stdout);
        
    }
    // 关闭文件
    fclose(src);
    fclose(dest);

fprintf

#include <stdio.h>
/*
int fprintf(FILE * stream, const char * format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。
参数:
       stream:已经打开的文件
       format:字符串格式,用法和printf()一样
返回值:
       成功:实际写入文件的字符个数
       失败:-1
*/
	int  year = 2018;
	int month = 10;
	int day = 27;
	char buf[1024] = "";
	FILE *fp = NULL;
	fp =  fopen("./fprintf.txt", "w");
	if (!fp)
	{
		   perror("");
		   return -1;
	}
	//sprintf(buf,"%04d:%02d:%02d\n",year,month,day);
	//fputs(buf,fp);
	fprintf(fp, "%04d:%02d:%02d\n", year, month, day);
	fclose(fp);
	system("pause");
	return 0;

fscanf

#include <stdio.h>
/*
int fscanf(FILE * stream, const char * format, ...);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
       stream:已经打开的文件
       format:字符串格式,用法和scanf()一样
返回值:
       成功:参数数目,成功转换的值的个数
       失败: - 1
*/
	int year = 0,month=0,day=0;
	FILE *fp = NULL;
	fp = fopen("./fprintf.txt", "r");
	if (!fp)
	{
		   perror("");
		   return -1;
	}
	fscanf(fp,"%d:%d:%d\n",&year,&month,&day);
	printf("%d  %d %d \n",year,month,day);
	system("pause");
	return 0;

fwrite


#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
/*
功能:以数据块的方式给文件写入内容
参数:
       ptr:准备写入文件数据的地址
       size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
       nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
       stream:已经打开的文件指针
返回值:
       成功:实际成功写入文件数据的块数目,此值和 nmemb 相等
       失败:0
    */
	STD num[3] = { {1,"lucy"},{2,"bob"},{3,"peter"} };
	FILE *fp = NULL;
	int cont = 0;
	fp = fopen("fwrite.txt","w");
	if (!fp)
	{
		   perror("");
		   return -1;
	}
	//fwrite 第二个参数写1 ,是为了返回值刚好是写入文件的字节数
	cont = fwrite(num, 1,sizeof(num),fp);
	//cont = fwrite(num,  sizeof(num), 1,fp);
	printf("cont=%d\n",cont);
	system("pause");

fread

#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
/*
功能:以数据块的方式从文件中读取内容
参数:
       ptr:存放读取出来数据的内存空间
       size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
       nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
       stream:已经打开的文件指针
返回值:
成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
       失败:0
*/

	STD num[3];
	memset(num,0,sizeof(num));
	FILE *fp = NULL;
	int cont = 0;
	fp = fopen("fwrite.txt", "r");
	if (!fp)
	{
		   perror("");
		   return -1;
	}
	fread(num,1,sizeof(num),fp);
	for (int i = 0; i < 3; i++)
	{
		   //cont = fread( &num[i] ,1,sizeof(STD),fp );
		   //printf("cont =%d\n",cont);
		   printf("%d %s\n",num[i].id,num[i].name);
	
	}
	fclose(fp);

fseek


#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
/*
功能:移动文件流(文件光标)的读写位置。
参数:
       stream:已经打开的文件指针
offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
       whence:其取值如下:
              SEEK_SET:从文件开头移动offset个字节
              SEEK_CUR:从当前位置移动offset个字节
              SEEK_END:从文件末尾移动offset个字节
返回值:
       成功:0
       失败:-1
       */
	FILE *fp = NULL;
	fp = fopen("fseek.txt", "w");
	if (!fp)
	{
		   perror("");
		   return -1;
	}
	fputs("helloworldheihei",fp);
	fseek(fp,0,SEEK_SET);//移动光标到头
	fputs("seek", fp);
	fseek(fp, -5, SEEK_END);//移动光标到头
	fputs("abc", fp);
	fclose(fp);

rewind

: 作用: 将光标移动到开头,和fseek(fp,0,SEEK_SET);

ftell

#include <stdio.h>
long ftell(FILE *stream);
/*
功能:获取文件流(文件光标)的读写位置。
参数:
       stream:已经打开的文件指针
返回值:
       成功:当前文件流(文件光标)的读写位置
       失败:-1
*/

stat

#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
/*
功能:获取文件状态信息
参数:
path:文件名
buf:保存文件信息的结构体
返回值:
成功:0
失败-1
 */
struct stat {
       dev_t         st_dev;         //文件的设备编号
       ino_t         st_ino;          //节点
       mode_t        st_mode;   //文件的类型和存取的权限
       nlink_t       st_nlink;     //连到该文件的硬连接数目,刚建立的文件值为1
       uid_t         st_uid;         //用户ID
       gid_t         st_gid;         //组ID
       dev_t         st_rdev;      //(设备类型)若此文件为设备文件,则为其设备编号
       off_t         st_size;        //文件字节数(文件大小)
       unsigned long st_blksize;   //块大小(文件系统的I/O 缓冲区大小)
       unsigned long st_blocks;    //块数
       time_t        st_atime;     //最后一次访问时间
       time_t        st_mtime;    //最后一次修改时间
       time_t        st_ctime;     //最后一次改变时间(指属性)
};

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
int main()
{
	struct stat buf;//buf结构体一定要有空间
	int ret = 0;
	ret = stat("fwrite.txt",&buf);
	if (ret < 0)//如果返回值小于0,代表文件不存在
	{
		   printf("file notfound\n");
	}
	printf("%d\n",buf.st_size);//buf.st_size 这个是文件大小
	system("pause");
	return 0;
}

linux和windwos \n的区别

![[Pasted image 20230901205341.png]]

删除文件,重命名

#include <stdio.h>
int remove(const char *pathname);
功能:删除文件
参数:
       pathname:文件名
返回值:
       成功:0
       失败:-1
 
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
功能:把oldpath的文件名改为newpath
参数:
oldpath:旧文件名
newpath:新文件名
返回值:
成功:0
失败: - 1

文件缓冲区

![[Pasted image 20230901205425.png]]

普通文件刷新缓冲区的方法,3种

  1. 缓冲区满
  2. fflush函数强制刷新
  3. 程序正常退出

windows下标准输出stdout文件,没有缓冲区的
linux 有
标准输入不能调用fflush强制刷新

案例:翻译软件

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#define FILENAME "dict.txt"

typedef struct _dict
{
    char *key;
    char *content;
}DICT;

// 初始化字典
// 因为要初始化一个指针变量,所以要拿到指针的地址,所以用二级指针来操作
void dict_INIT(DICT **temp)
{
    DICT *p = (DICT *)malloc(sizeof(DICT)*2);
    // 使用之前先申请空间,因为DICT里面都是字符指针变量
    p[0].key = (char *)malloc(sizeof("hello")+1);
    p[0].content = (char *)malloc(sizeof("你好")+1);
    p[1].key = (char *)malloc(sizeof("world")+1);
    p[1].content = (char *)malloc(sizeof("世界")+1);
    strcpy(p[0].key, "hello");
    strcpy(p[0].content, "你好");
    strcpy(p[1].key, "world");
    strcpy(p[1].content, "世界");
    *temp = p;
    
}
// 查找字典
int search_dict(char *cmd, DICT *dict, int len, char *content)
{
    int i;
    for(i = 0; i < len; i++)
    {
        if(strcmp(cmd, dict[i].key) == 0)
        {
            strcpy(content, dict[i].content);
            return 1;
        }
    }
    return 0;
}
int main(int argc, char const *argv[])
{
    DICT *dict = NULL;
    dict_INIT(&dict);
    char cmd[256] = "";
    char content[256] = "";
    while (1)
    {
        printf("请输入需要翻译的单词:");
        fgets(cmd, sizeof(cmd), stdin);
        cmd[strlen(cmd) - 1] = '\0';
        if (search_dict(cmd, dict, 2, content)) 
        {
            printf("%s 翻译为:%s\n", cmd, content);
        }
        else
        {
            printf("not translate\n");
        }
    }
    

    return 0;
}

贪吃蛇案例


#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdio.h>
#define WIDE 60
#define HIGH 16

// 1. 设置地图范围(边界) 宽 高
// 2. 初始化蛇, 初始化食物
// 3. 将蛇和食物显示在屏幕上
// 4. 蛇的移动(通过wasd按键控制蛇的移动方向
/*
    1. 蛇碰到墙
    2. 蛇碰到蛇的身体
    3. 蛇碰到障碍物
    4. 蛇碰到食物(蛇的身体增长一节,原食物消失,生成新的食物,增加分数)

*/
// 5. 蛇的死亡、积分

typedef struct snake_body
{
    int x, y;
} BODY;

// 把蛇相关的都写到一个结构体里
// 把变量都放到这里,结构体申请在堆区,不用来回地传参
typedef struct snake
{
    // 身体, 身体上的每一节坐标都是BODY类型
    BODY list[WIDE * WIDE];
    // 蛇的身体大小
    int length;
    // 食物的坐标
    BODY food;
    //    用来更新坐标
    COORD coord;
    //    蛇x和y移动的方向
    int dx, dy;

    //  得分
    int score;

    BODY tail;
} SNAKE;

void init_ui()
{
    for (int i = 0; i < HIGH; i++)
    {
        for (int j = 0; j < WIDE; j++)
        {
            printf("$");
        }
        printf("\n");
    }
}

// 初始化食物
void init_food(SNAKE *snake)
{
    // s设置随机数种子
    srand(time(NULL));
    // 初始化食物坐标
    snake->food.x = rand() % WIDE;
    snake->food.y = rand() % HIGH;
}

// 初始化蛇
void init_snake(SNAKE *snake)
{
    // 初始化蛇头坐标
    snake->list[0].x = WIDE / 2;
    snake->list[0].y = HIGH / 2;

    // 初始化蛇尾坐标
    snake->list[1].x = WIDE / 2 - 1;
    snake->list[1].y = HIGH / 2;

    init_food(snake);

    snake->dx = 1;
    snake->dy = 0;

    // 初始化蛇的长度
    snake->length = 2;

    snake->score = 0;
}
void show_ui(SNAKE *snake)
{
    // 显示蛇身体
    for (int i = 0; i < snake->length; i++)
    {
        //        这里需要转一下类型
        snake->coord.X = (short)snake->list[i].x;
        snake->coord.Y = (short)snake->list[i].y;
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);

        if (i == 0)
        {
            printf("@");
        }
        else
        {
            printf("$");
        }
    }

    snake->coord.X = (short)snake->food.x;
    snake->coord.Y = (short)snake->food.y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
    printf("$");

    // 将原来尾巴的位置显示为空格
    snake->coord.X = (short)snake->tail.x;
    snake->coord.Y = (short)snake->tail.y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
    printf(" ");
}

void move_snake(SNAKE *snake)
{
    // 记录尾巴的坐标
    snake->tail = snake->list[snake->length - 1];

    //  更新蛇的身体坐标,除去蛇头
    //  从倒数第二节身体开始,后一节的身体的坐标等于前一节身体的坐标
    for (int i = snake->length - 1; i > 0; i--)
    {

        snake->list[i] = snake->list[i - 1];
    }

    //    更新蛇头
    snake->list[0].x += snake->dx;
    snake->list[0].y += snake->dy;
}

void control_snake(SNAKE *snake)
{
    char key = 0;
    while (kbhit())
    {

        key = _getch();
    }

    switch (key)
    {
    case 'a':
        snake->dx = -1;
        snake->dy = 0;
        break;
    case 'd':
        snake->dx = 1;
        snake->dy = 0;
        break;
    case 'w':
        snake->dx = 0;
        snake->dy = -1;
        break;
    case 's':
        snake->dx = 0;
        snake->dy = 1;
        break;
    }
}

void game_end(SNAKE *snake)
{
    snake->coord.X = 25;
    snake->coord.Y = 25;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
    printf("game over, your score:%d\n", snake->score);
}

void snake_eat_self(SNAKE *snake)
{
    // 如果蛇头和蛇的身体的任意一节身体坐标相同,则为吃到自己
    for (int i = 1; i < snake->length; i++)
    {
        if (snake->list[0].x == snake->list[i].x &&
            snake->list[0].y == snake->list[i].y)
        {
            game_end(snake);
            exit(0);
        }
    }
}

void snake_eat_food(SNAKE *snake)
{
    // 如果蛇头和食物坐标重叠
    if (snake->list[0].x == snake->food.x &&
        snake->list[0].y == snake->food.y)
    {
        // 分数增加
        snake->score+=10;
        // 身体增长一节
        snake->length++;
        // 生成新的食物的同时,原食物已经消失了
        init_food(snake);
    }
    
}
void start_game(SNAKE *snake)
{
    //       蛇是否碰到墙
    while (snake->list[0].x < WIDE && snake->list[0].x >= 0 &&
           snake->list[0].y < HIGH && snake->list[0].y >= 0)
    {
        //       控制蛇的方向
        control_snake(snake);

        //       更新蛇的坐标
        //       蛇移动
        move_snake(snake);
        // system("clear");
        show_ui(snake);

        //       蛇是否碰到自己
        snake_eat_self(snake);

        //       蛇是否碰到食物(碰到食物,原食物消失,产生新的食物
        snake_eat_food(snake);

        //      延时0.5秒
        //      这里的大小写别写错了,如果用小写的sleep()无法实现延时
        Sleep(200);
    }
    game_end(snake);
}

void init_wall()
{
    for (int i = 0; i <= HIGH; i++)
    {
        for (int j = 0; j <= WIDE; j++)
        {
            if (j == 0 || j == WIDE || i == 0 || i == HIGH)
                printf("@");
            else
                printf(" ");
        }
        printf("\n");
    }
}

void hide_cur()
{
    // 隐藏控制台光标
    CONSOLE_CURSOR_INFO cci;
    cci.dwSize = sizeof(CONSOLE_CURSOR_INFO);
    cci.bVisible = FALSE;
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}
int main(int argc, char const *argv[])
{
    //     init_ui();

    SNAKE *snake = (SNAKE *)malloc(sizeof(SNAKE));

    // 隐藏控制台光标
    hide_cur();

    // 初始化墙
    init_wall();

    // 初始化蛇和食物
    init_snake(snake);
    show_ui(snake);

    start_game(snake);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值