如何从fopen转换为开放功能?

时间:2018-02-27 14:41:47

标签: c file

我似乎无法弄清楚如何从fopen转换为open。我没有多少经验,所以对我来说这是非常压倒性的。

这就是它本身的含义:

在cache_reader.c文件中(只是打开和关闭的函数):

void cr_close(cr_file* f){
free(f->buffer);
fclose(f->file);
}

cr_file* cr_open(char * filename, int buffersize)
{
    FILE* f;
    if ((f = fopen(filename, "r")) == NULL){
         fprintf(stderr, "Cannot open %s\n", filename);
         return 0; }

    cr_file* a=(cr_file*)malloc(sizeof(cr_file));
    a->file=f;
    a->bufferlength=buffersize;
    a->usedbuffer=buffersize;
    a->buffer=(char*)malloc(sizeof(char)*buffersize);
    refill(a);
    return a;
 }

在cache_reader.h文件中:

typedef struct{
   FILE* file;        //File being read
   int bufferlength;  //Fixed buffer length
   int usedbuffer;    //Current point in the buffer
   char* buffer;      //A pointer to a piece of memory
                 //  same length as "bufferlength"
 } cr_file;
 //Open a file with a given size of buffer to cache with
 cr_file* cr_open(char* filename, int buffersize);
 //Close an open file
 void cr_close(cr_file* f);
 int refill(cr_file* buff);

在cache_example.c文件中:

int main(){
char c;

 //Open a file
 cr_file* f = cr_open("text",20);  

 //While there are useful bytes coming from it
 while((c=cr_read_byte(f))!=EOF)
 //Print them
 printf("%c",c);

 //Then close the file
 cr_close(f);

//And finish
return 0;
}

我知道我需要改变fclose关闭,fopen打开。但是我不了解大多数其他的东西。我收到了大量的错误,我不知道这是如何用指针解决的,因为我几乎没有任何经验。我尝试使用int fileno(FILE * stream),通过说int fd = fileno(FILE * f)然后fd = fopen(filename,“r”))== NULL)。这不起作用,我可以找到的open函数的所有示例只使用文件的名称,而不是指定文件名的字符指针...我认为cr_close函数可以通过改变fclose来关闭,但这也不起作用。我不确定是否还需要编辑cache_example.c文件。

有人能提供一些帮助,让我走上正确的道路吗?

2 个答案:

答案 0 :(得分:1)

来自评论

练习的目的是保持示例代码不变,但是 重新实现其他代码以使用文件描述符而不是文件 流。 可悲的是,标题暴露了结构的内部,不必要地, 所以这个例子需要重新编译。 您将FILE *成员更改为int。 您不会使用任何带有文件流参数的函数。

标题(cache_reader.h)应包含此内容(而不是结构 定义):

typedef struct cr_file cr_file;

来源(cache_reader.c)应包含:

struct cr_file
{
    int file;
    int bufferlength;
    int usedbuffer;
    char *buffer;
};

这为您提供了客户端(示例)代码中的opaque类型,并允许 您无需重新编译客户端代码即可更改结构 (虽然你必须重新编译实现,当然 - 我们 无法完成奇迹)。

当然,无论何时,您都可以让客户重新编译代码 更改库的内部。 但是,如果你能做到,从长远来看往往更方便 库代码的更改和改进,无需使用 消费者(其他程序员)重新编译他们的代码。 二进制兼容性对于大型库非常重要,例如 给定平台上的标准C库。 对于像这样的小项目,没关系 - 但你需要 了解更大规模的问题,至少在适当的时候,如果你 坚持编程作为事业。

重写代码

请注意,我总结说我需要一些不同的成员来支持你 用例 - 我需要知道分配缓冲区的大小, 缓冲区中实际存在的数据量,以及当前位置 读。 我将成员重命名为bufmax(您的bufferlength),bufpos(您的 usedbuffer),并添加了buflen

我为cr_read_byte()编写了示例代码,它可以读取文件。

然而,要支持写作还有很多工作要做, 并在文件中一次移动一个字节,依此类推。

cache_reader.h

#ifndef CACHE_READER_H_INCLUDED
#define CACHE_READER_H_INCLUDED

typedef struct cr_file cr_file;

extern cr_file *cr_open(char *filename, int buffersize);
extern void cr_close(cr_file *f);
extern int cr_read_byte(cr_file *f);

#endif /* CACHE_READER_H_INCLUDED */

cache_reader.c

#include "cache_reader.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

struct cr_file
{
    int   file;     // File being read
    int   bufmax;   // Fixed buffer length
    int   bufpos;   // Current point in the buffer
    int   buflen;   // Amount of data in the buffer
    char *buffer;   // A pointer to a piece of memory
};

static void cr_refill(cr_file *f)
{
    if (f->bufpos >= f->buflen)
    {
        int nbytes = read(f->file, f->buffer, f->bufmax);
        if (nbytes > 0)
        {
            f->buflen = nbytes;
            f->bufpos = 0;
        }
    }
}

void cr_close(cr_file *f)
{
    free(f->buffer);
    close(f->file);
    free(f);
}

cr_file *cr_open(char *filename, int buffersize)
{
    int fd;
    if ((fd = open(filename, O_RDWR)) < 0)
    {
        fprintf(stderr, "cannot open %s for reading and writing (%d: %s)\n",
                filename, errno, strerror(errno));
        return 0;
    }

    cr_file *a = (cr_file *)malloc(sizeof(cr_file));
    char *b = (char *)malloc(sizeof(char) * buffersize);
    if (a == 0 || b == 0)
    {
        free(a);
        free(b);
        close(fd);
        fprintf(stderr, "cannot allocate %zu bytes of memory (%d: %s)\n",
                sizeof(cr_file) + buffersize, errno, strerror(errno));
        return 0;
    }
    a->file = fd;
    a->bufmax = buffersize;
    a->bufpos = 0;
    a->buflen = 0;
    a->buffer = b;
    return a;
}

int cr_read_byte(cr_file *f)
{
    if (f->bufpos >= f->buflen)
        cr_refill(f);
    if (f->bufpos >= f->buflen)
        return EOF;
    return f->buffer[f->bufpos++];
}

cache_example.c

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

int main(void)
{
    cr_file *f = cr_open("text", 20);
    if (f != 0)
    {
        int c;
        while ((c = cr_read_byte(f)) != EOF)
            putchar(c);
        cr_close(f);
    }
    return 0;
}

makefile

CFLAGS  = -std=c11 -O3 -g -Wall -Wextra
LDFLAGS =
LDLIBS  =

FILES.c = cache_example.c cache_reader.c
FILES.o = ${FILES.c:.c=.o}
FILES.h = cache_reader.h

PROG1 = cache_example

PROGRAMS = ${PROG1}

all: ${PROGRAMS}

${PROG1}: ${FILES.o}
    ${CC} -o $@ ${CFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}

${FILES.o}: ${FILES.h}

您可以在SOQ(堆栈)的GitHub上找到此代码(答案中显示的骨架makefile除外) 溢出问题)存储库作为文件 src/so-4901-1302子目录。

答案 1 :(得分:0)

以下提议的代码:

  1. 干净地编译
  2. 消除了不需要/未使用的代码
  3. 包含#include语句及其需要的原因
  4. 执行所需的功能
  5. 使用(根据OPs请求)文件描述符而不是文件指针
  6. 现在,建议的代码

    // following struct not actually used in this code
    #if 0
    typedef struct
    {
       int fd;               // file descriptor number of input file
       /*
        * int bufferlength;  // Fixed buffer length
        * int usedbuffer;    // Current point in the buffer
        * char* buffer;      // A pointer to a piece of memory
        *                    // same length as "bufferlength"
        * */
    } cr_file;
    #endif
    -------------------------
    
    // following 3 header files for 'open()' and 'O_RDONLY'
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    // following for 'read()' and 'close()'
    #include <unistd.h>
    
    // following for 'exit()' and 'EXIT_FAILURE'
    #include <stdlib.h>
    
    // following for 'printf()', 'perror()'
    #include <stdio.h>
    
    int main( void )
    {
        //Open a file
        int fd = open("text", O_RDONLY);
        if( 0 > fd )
        { // then open failed
            perror( "open for input file failed" );
            exit( EXIT_FAILURE );
        }
    
        // implied else, open successful
    
        //While there are useful bytes coming from it
        char buf;
    
        while( read( fd, &buf, 1 ) > 0 ) 
        {
            printf( "%c", buf );
        }
    
        //Then close the file
        close( fd );
    
        //And finish
        return 0;
    }