如果关闭未执行两次,则无法确定大小

could not determine size if fclose not done twice

本文关键字:两次 无法确定 执行 如果      更新时间:2023-10-16

我创建了一个File类,它是File类型的一种包装器,并添加了一些方法。

这是我的文件类的代码:
          #include <Fs/File.h>

File::File(Path& p):
    m_path(p),
    m_openned(false)
{
}
int File::open(const string& mode)
{
    m_f = new FILE;
    fopen(m_path, mode.c_str());
    if (m_f == NULL)
    {
        m_openned = false;
        return -1;
    }
    m_openned = true;
    return 0;
}
bool File::exists()
{
    FILE* file;
    if (file = fopen(m_path, "r"))
    {
        fclose(file);
        return true;
    }
    fclose(file);
    return false;
}
int File::flush(){
    return fflush(m_f);
}
int File::remove()
{
    return ::remove(m_path);
}
int File::close()
{
    if (isOpenned())
    {
        m_openned = false;
        return fclose(m_f);
    }
    return 0;
}
long File::getSize()
{
    struct stat file_status;
    if(!this->exists())
        return -1;
    if (stat(m_path, &file_status) < 0)
    {
        return -1;
    }
    return file_status.st_size;
}
FileMode File::getMode()
{
    struct stat file_status;
    if (stat(m_path, &file_status) < 0)
    {
        return FileMode(-1);
    }
    return FileMode(file_status.st_mode);
}

Path File::getPath()
{
    return m_path;
}

bool File::isOpenned()
{
    return m_openned;
}

int File::setMode(FileMode& mode)
{
    return chmod(m_path, mode);
}
int File::renameTo(File& f)
{
    if (f.exists() || !this->exists())
        return -1;
    return rename( m_path , f.getPath());
}
int File::copyTo(File& to)
{
    char ch;
    this->close();
    this->open(FileTypes::READ);
    to.close();
    to.open(FileTypes::WRITE);
    while (!this->eof())
    {
        ch = this->readc();
        if (ch == -1)
            return 0;
        if (!to.eof())
            to.writec(ch);
    }
    if (this->close() < 0)
    {
        return -1;
    }
    if (to.close() < 0)
    {
        return -1;
    }
    return 0;
}
int File::readc()
{
    if (!isOpenned())
        return FileTypes::ENDOFFILE;
    char c = fgetc(m_f);
    if (ferror(m_f))
    {
        return FileTypes::ENDOFFILE;
    }
    return c;
}
int File::writec(char c)
{
    if (!isOpenned())
        return -1;
    fputc(c, m_f);
    if (ferror(m_f))
    {
        return FileTypes::ENDOFFILE;
    }
    return 0;
}
bool File::eof()
{
    if (!isOpenned())
        return true;
    return feof(m_f);
}

我做了一些测试,我有一个问题

            Path p1("test.txt");
    Path p2("temp.txt");
    File f1(p1);
    File f2(p2);
    assert(f1.open(FileTypes::READ) == 0);
    assert(f1.exists() == true);
    assert(f1.close() == 0);
    cout<<"Mode of f1 "<<f1.getMode().getStringMode()<<endl;
    cout<<"Path of f1 "<<f1.getPath().getAbsolutePath()<<endl;
    cout<<"Size of f1 "<<f1.getSize()<<endl;
    assert(f2.exists() == false);
    assert(f1.copyTo(f2) == 0);
            //#####################################
             // If I comment f2.close() the                              
             // assert(f1.getSize() == f2.getSize()) test fails and                  
             // f2.getSize() == 0
             ##########################################
    f2.close();
    assert(f2.exists() == true);
    assert(f1.getSize() == f2.getSize());

我不明白为什么这个f2。close是必需的,因为我在copyTo方法中执行了close操作。有人能帮帮我吗?提前谢谢你。本

In File::copyTo:

    if (ch == -1)
        return 0;

您没有正确关闭文件就跳出了函数。当目标文件未关闭时,它的内容可能没有发送到操作系统,操作系统随后会报告伪造的文件大小。

fclose冲洗流。我的猜测是,在没有关闭文件的情况下,流还没有完全写入,所以大小不同。考虑在copyTo方法的末尾添加fflush(to);,以确保所有内容都已写入。

copyTo函数有多个出口,这并不能确保您实际关闭文件。在我看来,您可能提前退出了copyTo函数,并且预期的close没有执行

 while (!this->eof())
{
    ch = this->readc();
    if (ch == -1)
        return 0;
    if (!to.eof())
        to.writec(ch);
}

当您到达文件末尾时,您将获得EOF,在我的操作系统(windows)中它是-1,这将导致您在这里返回0,并跳过close call。