首页 > 解决方案 > Linux C Programming,尝试写:实现FILE系统模仿

问题描述

我正在尝试实现像 fopen、fclose、fputc 和 fgetc 这样的模拟文件系统。

一切都很好,除了写作(关闭时)。

当它使用 myfclose 关闭时,我想将缓冲区中的剩余字符(如果有)写入文件。但它返回错误 -1, Bad file descriptor

另一方面,如果我在 myfclose 函数中打开并新写入另一个文件,则没有问题。

我不知道它有什么问题。

这是代码:

我的文件.c

#include "mystdio.h"

int main()
{
    char c;
    MYFILE *fpin, *fpout;

    if((fpin = myfopen("a", "r")) == NULL) {
        perror("a");
        exit(-1);
    }
    if ((fpout = myfopen("b", "w")) == NULL) {
        perror("b"); exit(-1);
    }
    while((c = myfgetc(fpin)) != EOF) {
        myfputc(c, fpout);
    }
    myfclose(fpin); myfclose(fpout);
}

mystdio.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define BUFSIZE 1024
#define READONLY_MODE   0
#define WRITEONLY_MODE  1

typedef struct {
    int fd;
    char mode;
    char buf[BUFSIZE];
    int length;
    int offset;
} MYFILE;

MYFILE *myfopen(char *file, char *mode);
int myfclose(MYFILE *fp);
char myfgetc(MYFILE *fp);
void myfputc(char c, MYFILE *fp);

MYFILE *myfopen(char *file, char *mode) 
{
    MYFILE *fp = (MYFILE *)malloc(sizeof(MYFILE));
    if (fp != NULL) {
        // read mode
        if (strcmp(mode, "r") == 0) {
            if ((fp->fd = open(file, O_RDONLY)) < 0) {
                free(fp);
                return NULL;
            }
            fp->mode = READONLY_MODE;
        }
        else if (strcmp(mode, "w") == 0) {
            if ((fp->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
                free(fp);
                return NULL;
            }
            fp->mode = WRITEONLY_MODE;
        }
        else {
            fprintf(stderr, "not supported mode: %s\n", mode);
            free(fp);
            return NULL;
        }
        fp->length = fp->offset = 0;
    }
    return fp;
}

int myfclose(MYFILE *fp) 
{
    if (fp == NULL) return EOF;
    if (close(fp->fd) < 0) {
        free(fp);
        return EOF;
    }
    if (fp->mode == 1) {
        if (fp->length > fp->offset) {
            char buf[fp->offset - 1];
            memcpy(buf, fp->buf, (fp->offset - 1));
            buf[fp->offset - 1]  = '\0';
            printf("%d %s %lu\n", fp->fd, buf, sizeof(buf));

            // ERROR CODE: return bad descriptor
            if ((write(fp->fd, &buf, strlen(buf))) != strlen(buf)) {
                perror("Write");
            }
        }
    }
    
    free(fp);

    return 0;
}
char myfgetc(MYFILE *fp)
{
    if (fp == NULL) return EOF;
    if (fp->offset == fp->length) {
        if ((fp->length = read(fp->fd, fp->buf, BUFSIZE)) < 1) return EOF;
        fp->offset = 0;
    }
    return fp->buf[fp->offset++];
}
void myfputc(char c, MYFILE *fp) 
{
    if (fp == NULL) exit(-1);
    fp->length = BUFSIZE;
    if (fp->offset == fp->length) { 
        if ((write(fp->fd, fp->buf, BUFSIZE)) < BUFSIZE) {
            fprintf(stderr, "failed to write");
            exit(-1);
        }
        fp->offset = 0;
    }
    fp->buf[fp->offset++] = c;
}

标签: clinuxfilesystem-callswrite

解决方案


一个关键的错误是c需要声明为int因为EOF不能用char.

另一个错误是您在以myfclose. 由于显而易见的原因,这将不起作用。关闭文件应该是你做的最后一件事。

改成:

int myfclose(MYFILE *fp) 
{
    if (fp == NULL) return EOF;

    if (fp->mode == 1) {
        if (fp->length > fp->offset) {
            char buf[fp->offset - 1];
            memcpy(buf, fp->buf, (fp->offset - 1));
            buf[fp->offset - 1]  = '\0';
            printf("%d %s %lu\n", fp->fd, buf, sizeof(buf));

            // ERROR CODE: return bad descriptor
            if ((write(fp->fd, &buf, strlen(buf))) != strlen(buf)) {
                perror("Write");
            }
        }
    }

    if (close(fp->fd) < 0) {
        free(fp);
        return EOF;
    }
    
    free(fp);

    return 0;
}

可能还有其他错误,但上面修复了其中两个。


推荐阅读