zoukankan      html  css  js  c++  java
  • C语言讲义——文件操作

    fopen( ) 函数:创建一个新的文件或者打开一个已有的文件

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

    关于参数mode的取值

    r
    w 写(无文件则创建)(从头写)
    a 写(无文件则创建)(追加)
    r+ 读写
    w+ 读写。如果文件存在,则截断为零长度,如果文件不存在,则创建一个新文件。
    a+ 从头读,追加写(无文件则创建)

    新建 从头 追加
    r
    w
    a
    r+
    w+
    a+

    写文件示例

    #include <stdio.h>
    
    int fileWrite() {
    	FILE *fp = NULL;
    
    	fp = fopen("test.txt", "a+");
    	if(NULL == fp) {
    		// 将文件设为"只读",可测此处代码
    		puts("fopen出错");
    		// 使用perror()显示错误信息
    		perror("fopen() Err");
    		return -1;
    	}
    	fprintf(fp, "云想衣裳花想容,春风拂槛露华浓。
    ");
    	fputs("若非群玉山头见,会向瑶台月下逢。
    ", fp);
    
    	fclose(fp);
    	return 0;
    }
    main() {
    	fileWrite();
    }
    

    读文件示例

    #include <stdio.h>
    
    int  fileRead() {
    	FILE *fp = NULL;
    	char buff[255];
    
    	fp = fopen("test.txt", "r");
    	if(NULL == fp) {
    		perror("fopen Error");
    		return -1;
    	}
    	fscanf(fp, "%s", buff);
    	printf("读取到空白字符: %s
    ", buff );
    
    	fgets(buff, 255, (FILE*)fp);
    	printf("读取一行: %s
    ", buff );
    
    	fclose(fp);
    	return 0;
    }
    main() {
    	fileRead();
    }
    

    偏移

    	fp = fopen(g_sFile, "r");
    	// int fseek(FILE *stream, long offset, int fromwhere);
    	// 第一个参数stream为文件指针
    	// 第二个参数offset为偏移量,整数表示正向偏移,负数表示负向偏移
    	// 第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
    	// SEEK_SET:文件开头(0)
    	// SEEK_CUR:当前位置(1)
    	// SEEK_END:文件结尾(2)
    	// 定位成功:返回0
    	// 定位失败:返回非0
    	fseek(fp,1,SEEK_CUR);
    

    示例:修改指定人员的成绩记录

    现有成绩文件: data.dat

    Apple,100;
    Banana,098;
    Cat,060;
    Dog,032;
    

    修改Cat的成绩为59分,即[Cat,060;]→[Cat,059;]前后内容都不变
    为了方便定位,约定成绩都是3位字符表示

    SEEK_CUR版

    偏移数值问题——Unix和Windows不同

    Unix(不算LF):fseek(fp, -4, SEEK_CUR)
    

    Windows(算CR LF):fseek(fp, -6, SEEK_CUR)
    

    SEEK_SET版

    即使使用SEEK_SET从头找,找到上一行尾,再加,也有区别:

    Unix:fseek(fp, nCurLen+4, SEEK_SET);
    WIndows:fseek(fp, nCurLen+6, SEEK_SET);
    

    结论:CRLF在内存中是不同的,所以fseek的参数有差别;但是反映在字符串上,都是一个 (ASCII 10),比如第一行,strlen都是11

    参考代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int updateFile() {
    	int nRet = 0;
    	FILE * fp = NULL;
    
    	fp = fopen("data.dat", "r+");// r+:读写
    	if (NULL == fp) {
    		perror("fopen() Err");
    		return 0;
    	}
    	// 读取文件
    	char buff[1024]= {0};
    	while(fgets(buff, 1024, fp)) {
    		// char *strstr(char *str1, const char *str2);
    		// 判断字符串str2是否是str1的子串。
    		// 是:返回str2在str1中首次出现的地址;
    		// 否:返回NULL
    		if(strstr(buff, "Cat") != NULL) {
    			//此时"光标"在读到的内容后面
    			int nSeek = fseek(fp, -6, SEEK_CUR);
    			if(nSeek != 0) {
    				perror("fseek");
    				break;
    			} else {
    				// 修改文件
    				fprintf(fp, "%s", "059");
    				nRet = 1;
    				break;
    			}
    		}
    	}
    	// 无果:关闭文件
    	fclose(fp);
    	return nRet;
    }
    int main(int argc, char *argv[]) {
    	updateFile();
    
    	return 0;
    }
    

    应用:读写log

    #include <stdio.h>
    #include <io.h>
    #include <time.h>
    #include <direct.h>
    
    enum Level { DEBUG, INFO, WARING, ERROR};
    
    const char* g_sDir = "temp";
    const char* g_sFile = "temp/info.txt";
    
    void getTime(char* sTime_o) {
    	time_t _time;
    	time(&_time);
    	struct tm *p =localtime(&_time);
    
    	// 格式化,并写入到字符串中
    	sprintf(sTime_o, "%d-%02d-%02d %02d:%02d:%02d",
    	        p->tm_year+1900,
    	        p->tm_mon + 1,
    	        p->tm_mday,
    	        p->tm_hour,
    	        p->tm_min,
    	        p->tm_sec);
    }
    int makeDir() {
    	// access:判断文件或文件夹是否存在
    	// <io.h>
    	// F_OK:判断是否存在
    	// success:0
    	// fault:-1
    	if (access(g_sDir, F_OK ) == 0) {
    		// 文件夹存在
    	} else {
    		// _mkdir:创建文件夹
    		// <direct.h>
    		// success:0
    		// fault:-1
    		if (_mkdir(g_sDir) == -1) {
    			printf("创建文件夹失败");
    			return -1;
    		}
    
    	}
    	return 0;
    }
    int logWrite(Level lvl, char*msg) {
    	// 获取时间
    	char sTime_o[200];
    	getTime(sTime_o);
    	//-------------------------
    	// 创建log文件夹
    	if(makeDir() == -1) {
    		return -1;
    	}
    	// 打开文件
    	FILE *fp = NULL;
    	fp = fopen(g_sFile, "a+");
    	if(NULL == fp) {
    		printf("无法打开文件%s
    ", g_sFile);
    		return -1;
    	}
    	// 根据log级别,写入log
    	if (lvl == DEBUG) {
    		fprintf(fp, "%s [DEBUG] %s
    ",sTime_o,msg);
    	} else if(lvl == INFO) {
    		fprintf(fp, "%s [INFO] %s
    ",sTime_o,msg);
    	}
    	fclose(fp);
    	return 0;
    }
    int logRead() {
    	FILE *fp = NULL;
    	fp = fopen(g_sFile, "r");
    	if(NULL == fp) {
    		puts("文件读取失败");
    		return -1;
    	}
    
    	//TEST: 当前位置右移1
    	fseek(fp,1,SEEK_CUR);
    
    	// 读取文件
    	char buff[255] = {0};
    	while(fgets(buff, 255, (FILE*)fp)!=NULL) {
    		printf("> %s", buff );
    	}
    	fclose(fp);
    	return 0;
    }
    main() {
    	// 能写,才读;不写,不读
    	if (logWrite(INFO,"郭德纲") == 0) {
    		logRead();
    	}
    }
    
  • 相关阅读:
    谷粒商城心得(四)
    centos7设置rc.local开机执行命令
    密码学简介
    如何解决 kubernetes 重启后,启来不来的问题
    谷粒商城安装ES及入门(十六)
    谷粒商城读写分离(十五)
    谷粒商城创建mysql主从(十四)
    虚拟机LVM在线扩容
    Builder 模式初探
    Mysql 导入实战
  • 原文地址:https://www.cnblogs.com/tigerlion/p/11191753.html
Copyright © 2011-2022 走看看