文件及二进制文件

文件


1.格式化输入输出


    格式化的输入输出
printf
    %[flags][width][.prec][hlL]type
scanf
    %[flag]type 
    
    %[flags][width][.prec][hlL]type
    
Flag: -、+、(space)、0
含义:左对齐、在前面放+或-、正数留空、0填充

width或prec:number、*、.number、.*
含义:最小字符数、下一个参数是字符数、小数点后的位数、下一个参数是小数点后的位数

类型修饰:hh、h、l、ll、L
含义:单个字节、short、long、long long、long double

    printf和scanf的返回值
读入的项目数
输出的字符数

在要求严格的程序中,应该判断每次调用scanf或printf的返回值,从而了解程序运行中是否存在问题

2.文件输入输出


    文件输入输出
用>和<做重定向,<输入,>输出  

    FILE
 

FILE* fopen(const char* restrict path, const char* restrict mode);
int fclose(FILE *stream);
fscanf(FILE*, ...)    

打开文件的标准代码
 

FILE* fp=fopen("file","r");
if(fp){
    fscanf(fp,...);
    fclose(fp);
}else{
    ...

  }
fprintf(FILE*, ...)
#include <stdio.h>

int main(int argc, char const* argv[]) {
    FILE* fp = fopen("12.in", "r");
    if (fp) {
        int num;
        fscanf(fp, "%d", &num);
        printf("%d\n", num);
        fclose(fp);
    }
    else {
        printf("无法打开文件。\n");
    }
    return 0;
}


3.二进制文件


    二进制文件
其实所有的文件最终都是二进制的
文本文件无非是用最简单的方式可以读写的文件
    more、tail
    cat
    vi
而二进制文件是需要专门的程序来读写的文件
文本文件的输入输出是格式化,可能经过转码

    文本VS二进制
Unix喜欢用文本文件来做数据存储和程序配置
    交互式终端的出现使得人们喜欢用文本和计算机"talk"
    Unix的shell提供了一些读写文本的小程序
Windows喜欢用二进制文件
    DOS是草根文化,并不继承和熟悉Unix文化    PC刚开始的时候能力有限,DOS的能力更有限,二进制更接近底层
    
    文本VS二进制
文本的优势是方便人类读写,而且跨平台
文本的确定是程序输入输出要经过格式化,开销大
二进制的缺电是人类读写困难,而且不跨平台
    int的大小不一致,大小端的问题...
二进制的优点是程序读写快

    程序为什么要文件
配置
    Unix用文本,Windows用注册表
数据
    稍微有点量的数据都放数据库了
媒体
    这个只能是二进制的
现实是,程序通过第三方库来读写文件,很少直接读写二进制文件了

    二进制读写
size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);

size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
注意FILE指针是最后一个参数
返回的是成功读写的字节数

    为什么nitems
因为二进制文件的读写一般都是通过对一个结构变量的操作来进行的
于是nitem就是用来说明这次读写几个结构变量!
    
student.h

#pragma once

const int STR_LEN = 20;
typedef struct _student {
    char name[STR_LEN];
    int gender;
    int age;
} Student;

run_app.c

#include <stdio.h>
#include "student.h"

void getList(Student aStu[], int number);
int save(Student aStu[], int number);

int main(int argc, char const* argv[]) {
    int number = 0;
    printf("输入学生数量:");
    scanf("%d", &number);
    Student aStu[number];

    getList(aStu, number);
    if (save(aStu, number)) {
        printf("保存成功。\n");
    }
    else {
        printf("保存失败。\n");
    }

    return 0;
}

void getList(Student aStu[], int number) {
    char format[STR_LEN];
    //sprintf向一个字符串输出,%%表示输出一个%
    //"%19s"
    sprintf(format, "%%%ds", STR_LEN - 1);
    
    int i;
    for (i = 0; i < number; i++) {
        printf("第%d个学生:\n", i);
        printf("\t姓名:");
        scanf(format, aStu[i].name);
        printf("\t性别(0-男,1-女,2-其他):");
        scanf("%d", &aStu[i].gender);
        printf("\t年龄:");
        scanf("%d", &aStu[i].age);
    }
}

int save(Student aStu[], int number) {
    int ret = -1;
    FILE* fp = fopen("student.data", "w");
    if (fp) {
        ret = fwrite(aStu, sizeof(Student), number, fp);
        fclose(fp);
    }
    return ret==number;
}

    在文件中定位
long ftell(FILE *stream);
int fseek(FILE *stream, long offset, int whence);
    SEEK_SET:从头开始
    SEEK_CUR:从当前位置开始
    SEEK_END:从尾开始(倒过来)    

加了查看数据的功能:

#include <stdio.h>
#include "student.h"

void getList(Student aStu[], int number);
int save(Student aStu[], int number);
void read(FILE* fp, int index);

int main(int argc, char const* argv[]) {
    int number = 0;
    printf("输入学生数量:");
    scanf("%d", &number);
    Student aStu[number];

    getList(aStu, number);
    if (save(aStu, number)) {
        printf("保存成功。\n");
    }
    else {
        printf("保存失败。\n");
    }

    FILE* fp = fopen("student.data", "r");
    if (fp) {
        fseek(fp, 0L, SEEK_END);
        long size = ftell(fp);
        int number = size / sizeof(Student);
        int index = 0;
        printf("有%d个数据,你要看第几个?\n请输入:", number);
        scanf("%d", &index);
        read(fp, index - 1);
        fclose(fp);
    }

    return 0;
}

void read(FILE* fp, int index) {
    fseek(fp, index * sizeof(Student), SEEK_SET);
    Student stu;
    if (fread(&stu, sizeof(Student), 1, fp) == 1) {
        printf("第%d个学生:", index + 1);
        printf("\t姓名:%s\n", stu.name);
        printf("\t性别:");
        switch (stu.gender) {
        case 0:printf("男\n"); break;
        case 1:printf("女\n"); break;
        case 2:printf("其他\n"); break;
        }
        printf("\t年龄:%d\n", stu.age);
    }
}

void getList(Student aStu[], int number) {
    char format[STR_LEN];
    //sprintf向一个字符串输出,%%表示输出一个%
    //"%19s"
    sprintf(format, "%%%ds", STR_LEN - 1);
    
    int i;
    for (i = 0; i < number; i++) {
        printf("第%d个学生:\n", i);
        printf("\t姓名:");
        scanf(format, aStu[i].name);
        printf("\t性别(0-男,1-女,2-其他):");
        scanf("%d", &aStu[i].gender);
        printf("\t年龄:");
        scanf("%d", &aStu[i].age);
    }
}

int save(Student aStu[], int number) {
    int ret = -1; 
    FILE* fp = fopen("student.data", "w");
    if (fp) {
        ret = fwrite(aStu, sizeof(Student), number, fp);
        fclose(fp);
    }
    return ret==number;
}

    可移植性
这样的二进制文件不具有可移植性
    在int为32位的机器上写成的数据文件无法直接在int位64位的机器上正确读出
解决方案之一是放弃使用int,而是typedef具有明确大小的类型
更好的方案是用文本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值