【问题标题】:How to convert from fopen to open function?如何从 fopen 转换为 open 函数?
【发布时间】:2018-02-27 14:41:46
【问题描述】:

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

这是它自己的东西:

在 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 更改为 close 来完成,但这也不起作用。我不确定是否还需要编辑 cache_example.c 文件。

谁能提供一些帮助,让我走上正确的道路……?

【问题讨论】:

  • 你觉得文件名和指向char的指针有什么区别?
  • 练习的目的是保持示例代码不变,但重新实现其他代码以使用文件描述符而不是文件流。遗憾的是,标题不必要地暴露了结构的内部,因此需要重新编译示例。您将FILE * 成员更改为int。您不会使用任何带有文件流参数的函数。
  • 如何将 FILE * 更改为 int..?我认为 fileno 函数会做我试图做的事情。我还尝试将 fprintf 更改为 printf 并将 stderr 更改为 stdout 以使其工作。还是不行。
  • 注意:更改char c --> int c 以避免不正确的行为。

标签: c file


【解决方案1】:

来自 cmets

练习的目的是保持示例代码不变,但是 重新实现其他代码以使用文件描述符而不是文件 流。 可悲的是,标题不必要地暴露了结构的内部, 所以这个例子需要重新编译。 您将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;
};

这会在客户端(示例)代码中为您提供一个不透明的类型,并允许 您无需重新编译客户端代码即可更改结构 (当然,尽管您必须重新编译实现——我们 不能创造完整的奇迹)。

当然,您可以让您的客户重新编译他们的代码 对库的内部进行更改。 但是,从长远来看,如果您可以 更改和改进您的库代码,而无需 消费者(其他程序员)重新编译他们的代码。 二进制兼容性对于大型库非常重要,例如 给定平台上的标准 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 子目录。

【讨论】:

  • 你可以给 Leffler 教授上一堂完整的课。
  • @DavidC.Rankin:谢谢。我觉得另一个答案并没有真正帮助那么多,尽管有一些危险这太过分了。我没有指出代码中的所有细微之处,但这可能有压倒 OP 的危险。
  • 我一直很欣赏那些布局合理且合理的例子,我每次都能学到一些东西——这是美好的一天。
  • 由于我目前的编程水平,我怀疑我能否完全理解这些小事,但我已经能够通过查看这个代码来相应地转换我的代码以获得我想要的东西。感谢您的宝贵时间。
【解决方案2】:

以下建议的代码:

  1. 干净编译
  2. 消除不需要/未使用的代码
  3. 包括#include 语句以及为什么需要它们
  4. 执行所需的功能
  5. 使用(根据 OP 请求)文件描述符而不是文件指针

现在,建议的代码

// 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;
}

【讨论】:

  • 谢谢你的例子,它很容易理解。
【解决方案3】:

请注意,我有两个选择,我可以将fopen 中的open 转换为如上所述的fcntl.h,但这需要我在现有代码库中更改很多函数签名FILE *int。相反,我决定使用fflushfsync,结果证明这是一个更简单的解决方案,同时仍确保文件内容立即写入磁盘。 fflushfsync 更容易的原因是它们仍然允许我使用现有的 FILE 指针。然后为了确保我的文件立即写入磁盘,我使用以下内容。这基本上为您提供了一个潜在的替代解决方案:

FILE *fp = fopen(myfilename, "w+");

if (fp) {
    // write contents of buffer to OS
    if (0 != fflush(fp)) {
        // error handling here
    }

    // Tell OS to write contents of buffers to storage media
    if (0 != fsync(fileno(fp))) {
        // more error handling
    } else {
        // steps to do on success
    }
} else {
    // debug log could not complete task
}

这就是chqrlie 在这篇文章中的解释: Difference between fflush and fsync

【讨论】:

    猜你喜欢
    • 2011-04-06
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多