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, "云想衣裳花想容,春风拂槛露华浓。\n");
    fputs("若非群玉山头见,会向瑶台月下逢。\n", 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\n", buff );

    fgets(buff, 255, (FILE*)fp);
    printf("读取一行: %s\n", 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)

1648799-20190715214545969-356079854.png

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

1648799-20190715214605925-1086461646.png

SEEK_SET版

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

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

结论:CRLF在内存中是不同的,所以fseek的参数有差别;但是反映在字符串上,都是一个\n(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\n", g_sFile);
        return -1;
    }
    // 根据log级别,写入log
    if (lvl == DEBUG) {
        fprintf(fp, "%s [DEBUG] %s\n",sTime_o,msg);
    } else if(lvl == INFO) {
        fprintf(fp, "%s [INFO] %s\n",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();
    }
}

转载于:https://www.cnblogs.com/tigerlion/p/11191753.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值