文件打开、关闭的统一管理。
打开文件 —— 处理文件 —— 关闭文件。
那么文件访问的结构体里必须包含文件名、处理方法。这次我们多加一个成员 —— 访问模式。于是
file_reader.h
#ifndef _FILE_READER_H_
#define _FILE_READER_H_
#include <stdio.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FileAcessorContext{
const char * const pFname;
const char * const pMode;
void (* const processor)(struct FileAcessorContext *pThis, FILE *fp);
}FileAcessorContext;
bool access_file(FileAcessorContext *pCtx);
#ifdef __cplusplus
}
#endif
#endif
file_reader.c
#include "file_reader.h"
bool access_file(FileAcessorContext *pCtx){
FILE *fp = fopen(pCtx->pFname, pCtx->pMode);
if(fp == NULL)
return false;
pCtx->processor(pCtx, fp);
fclose(fp);
return true;
}
内存的管理与释放 和上面是完全一样的。
分配内存 —— 内存的处理 —— 释放内存。 于是
buffer.h
#ifndef _BUFFER_H_
#define _BUFFER_H_
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct BufferContext{
void *pBuf;
size_t size;
void (* const processor)(struct BufferContext *pThis);
}BufferContext;
bool buffer(BufferContext *pThis);
#ifdef __cplusplus
}
#endif
#endif
buffer.c
#include "buffer.h"
bool buffer(BufferContext *pThis){
pThis->pBuf = malloc(pThis->size);
if(pThis->pBuf == NULL)
return false;
pThis->processor(pThis);
free(pThis->pBuf);
return true;
}
接下来这个获取文件内数值的范围,就比较麻烦了。主要是因为打开、关闭文件、内存分配、释放的处理。
内存的分配又需要先知道文件的大小,要知道文件的大小首先要打开文件,获得了大小又要有一个变量来存储它,以备后续使用。
所以 获取文件大小的上下文结构体应该是要继承文件访问结构体,并加上一个变量size。
所以
typedef struct {
FileAcessorContext base;
long size;
}FileSizeGetterContext;
当获取文件大小时,我们仅有的信息是文件名,所以我们的file_size函数应该这样写:
static long file_size(const char * const pFname);
具体的实现是要定义一个FileSizeGetterContext(获取文件大小的上下文结构体)变量ctx。
这样访问文件之后,可以把文件大小保存在ctx的成员size里。如下:
static long file_size(const char * const pFname){
FileSizeGetterContext ctx = {{pFname, "r", size_reader}, 0};
if(!access_file(&ctx.base)){
return -1;
}
return ctx.size;
}
按照这样的想法去写内存的分配、内存的操作、文件访问失败的处理,内存分配失败的处理。
内存的操作又包括读取文件的内容到内存,然后将内存做我们想要的处理,返回相应的结果。
int_range.h
#ifndef _INT_RANGE_H_
#define _INT_RANGE_H_
#include "file_reader.h"
#include "buffer.h"
#include "limits.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
FileAcessorContext base;
long size;
}FileSizeGetterContext;
typedef enum {
ERR_CAT_OK,
ERR_CAT_FILE,
ERR_CAT_MEMORY
}IntRangeError;
typedef struct {
const char * const pFname;
int errorCatgory;
}Context;
typedef struct {
BufferContext base;
Context *pAppCtx;
}MyBufferContext;
typedef struct {
FileAcessorContext base;
MyBufferContext *pBufCtx;
}MyFileAccessorContext;
IntRangeError int_range(const char * const pFname);
static long file_size(const char * const pFname);
static void size_reader(FileAcessorContext *p, FILE *fp);
static long buffer_allocate(long size, Context *pAppCtx);
static void file_error(Context *pCtx);
static void buffer_error(Context *pCtx);
static void do_with_buffer(BufferContext *p);
static void reader(FileAcessorContext *p, FILE *fp);
static void writer(FileAcessorContext *p, FILE *fp);
static int range_processor(char *buf, size_t size);
#ifdef __cplusplus
}
#endif
#endif
int_range.c
#include "int_range.h"
static long file_size(const char * const pFname){
FileSizeGetterContext ctx = {{pFname, "r", size_reader}, 0};
if(!access_file(&ctx.base)){
return -1;
}
return ctx.size;
}
static void size_reader(FileAcessorContext *p, FILE *fp){
FileSizeGetterContext *pThis = (FileSizeGetterContext *)p;
pThis->size = -1;
if(fseek(fp, 0, SEEK_END) == 0)
pThis->size = ftell(fp);
}
static long buffer_allocate(long size, Context *pAppCtx){
MyBufferContext bufCtx = {{NULL, size, do_with_buffer}, pAppCtx};
if(!buffer(&bufCtx.base)){
return -1;
}
return size;
}
IntRangeError int_range(const char * const pFname){
Context ctx = {pFname, ERR_CAT_OK};
long size = file_size(pFname);
if(size == -1){
file_error(&ctx);
return ctx.errorCatgory;
}
long buffer_size = buffer_allocate(size, &ctx);
if(buffer_size == -1){
buffer_error(&ctx);
return ctx.errorCatgory;
}
}
static void file_error(Context *pCtx){
printf("Failed to open File: %s\n", pCtx->pFname);
pCtx->errorCatgory = ERR_CAT_FILE;
}
static void buffer_error(Context *pCtx){
printf("Failed to malloc memory\n");
pCtx->errorCatgory = ERR_CAT_MEMORY;
}
static void do_with_buffer(BufferContext *p) {
MyBufferContext *pBufCtx = (MyBufferContext *)p;
MyFileAccessorContext readFileCtx = {{pBufCtx->pAppCtx->pFname, "rb", reader}, pBufCtx};
if(!access_file(&readFileCtx.base)){
file_error(pBufCtx->pAppCtx);
return;
}
int value = range_processor(p->pBuf, p->size);
printf("value is %d\n", value);
MyFileAccessorContext writeFileCtx = {{pBufCtx->pAppCtx->pFname, "wb", writer}, pBufCtx};
if(!access_file(&readFileCtx.base)){
file_error(pBufCtx->pAppCtx);
return;
}
}
static void reader(FileAcessorContext *p, FILE *fp){
MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p;
MyBufferContext *pBufCtx = pFileCtx->pBufCtx;
if(pBufCtx->base.size != fread(pBufCtx->base.pBuf, 1 , pBufCtx->base.size, fp)){
file_error(pBufCtx->pAppCtx);
}
}
static void writer(FileAcessorContext *p, FILE *fp){
MyFileAccessorContext *pFileCtx = (MyFileAccessorContext *)p;
MyBufferContext *pBufCtx = pFileCtx->pBufCtx;
if(pBufCtx->base.size != fwrite(pBufCtx->base.pBuf, 1, pBufCtx->base.size, fp)){
file_error(pBufCtx->pAppCtx);
}
}
static int range_processor(char *buf, size_t size){
int min = INT_MAX;
int max = INT_MIN;
for(int i = 0; i < size; i+=4){
min = min > (*(int *)(buf + i)) ? (*(int *)(buf + i)) : min;
max = max < (*(int *)(buf + i)) ? (*(int *)(buf + i)) : max;
}
return max - min;
}
测试文件很简单
range_test.c
#include "int_range.h"
int main(int argc, char const *argv[])
{
int_range("nums.bat");
return 0;
}
nums.bat里是若干个int型数据。函数返回这些数据的数值范围。