【问题标题】:Can fseek() be used to insert data into the middle of a file? - C可以使用 fseek() 将数据插入文件中间吗? - C
【发布时间】:2012-11-17 23:46:00
【问题描述】:

我知道函数 fseek() 可用于将数据输出到文件中的特定位置。但我想知道我是否使用 fseek() 移动到文件中间然后输出数据。新数据会覆盖旧数据吗?例如,如果我有一个包含 123456789 的文件,并且我在 5 之后使用 fseek() 输出 newdata,那么该文件将包含 12345newdata6789 还是包含 12345newdata。

【问题讨论】:

    标签: c insert fseek


    【解决方案1】:

    在文件的“中间”写入数据会覆盖现有数据。所以你会有'12345newdata'。


    编辑:正如下面的 cmets 所述,应该注意的是,这会覆盖数据而不截断文件的其余部分。作为示例的扩展版本,如果您在包含1234567890ABCDEFG 的文件中的5 之后写newdata,那么您将拥有12345newdataCDEFGnot 12345newdata

    【讨论】:

    • 它不会截断整个文件。但它会覆盖已写入位置的数据。
    • 啊,真的。文件中没有足够的数据来查看差异。对不起。不过,我认为值得在答案中提及。
    【解决方案2】:

    是的,它允许您这样做,这些文件称为“随机访问文件”。假设您已经有一个设置文件(结构但为空),在这种情况下,您可以填充您想要的“槽”,或者在槽充满数据的情况下,您可以覆盖它。

    typedef struct{
        int number;
        char name[ 20 ];
        char lastname[ 20 ];
        float score;
    }students_t;
    
    /* Supposing that you formatted the file already and the file is opened. */
    /* Imagine the students are listed each one has a record. */
    
    void modifyScore( FILE * fPtr ){
        students_t student = { 0, "", "", 0.0 };
        int nrecord;
        float nscore;
    
        printf( "Enter the number of the student:" );
        scanf( "%d", &record )
        printf( "Enter the new Score:" );
        scanf( "%f", &nscore ); // this is a seek example so I will not complicate things.
    
        /*Seek the file ( record - 1 ), because the file starts in position 0 but the list starts in 1*/
        fseek( fPtr, ( record  - 1  ) * sizeof ( students_t ), SEEK_SET );
    
        /* Now you can read and copy the slot */
        fread( fPtr, "%d%s%s%f", &student.number, student.name, student.lastname, &student.score );
    
        /* Seek again cause the pointer moved. */
        fseek( fPtr, ( record  - 1  ) * sizeof ( students_t ), SEEK_SET );
        student.score = nscore;
    
        /*Overwrite his information, only the score will be altered. */
        fwrite( &student, sizeof( student_t ), 1, fPtr );
    }
    

    它是这样工作的(图片来自Deitel-How to program in C 6th Edition):

    【讨论】:

    • @Bonsanto 我是否必须将整个文件加载到内存中才能使您的方法起作用?我试图完成的目标是将文件的一部分提取到内存中(而不是整个文件),编辑它们,然后将数据“保存”到文件中,而不替换任何未提取的数据。
    • 您只需要一个格式化文件,在我的示例中使用旁路复制您要编辑的插槽(学生变量),修改您想要的成员,然后再次查找,然后覆盖该插槽
    • @Bonstanto 首先非常感谢您迄今为止的帮助。但我是 C 新手,有点困惑。据我了解,您寻求将文件扔到您要编辑的部分,然后将其作为结构编辑提取到内存中,然后将其输出回文件中的同一位置。我接近了吗?如果新数据超过旧数据的字节大小,这种方法是否仍然有效?
    • 你非常接近,但如果你使用随机访问文件,你必须确保你的结构足够健壮以保持最大允许值。这是一个相关的帖子:stackoverflow.com/questions/13438941/…
    • @Mawg 我从 Deitel 的 Learn to Program in C 中提取了它。顺便说一句,应该添加学分
    【解决方案3】:

    您可能知道这一点,但 fseek() 只是移动相关的位置指示符,并没有规定执行中的输出函数是覆盖还是插入。

    您可能正在使用fwrite() 或其他一些普通的普通输出函数,这些将覆盖,为您提供“12345newdata”而不是插入的变体。

    另一方面,你可以滚动你自己的插入函数(我不认为有一个股票的 stdio.h 函数),并在 fseek() 之后调用它以获得你想要的插入。

    这样就足够了:

    insert(const void *ptr, size_t len, FILE *fp) {
        char tmp[len];
        size_t tmplen;
    
        while (len) {
            // save before overwriting
            tmplen = fread(tmp, 1, sizeof(tmp), fp);
            fseek(fp, -tmplen, SEEK_CUR);
    
            // overwrite
            fwrite(ptr, len, 1, fp);
    
            // reloop to output saved data
            ptr = tmp;
            len = tmplen;
        }
    }
    

    fread()fwrite() 的错误处理省略了冗长。)

    【讨论】:

    • Antak 感谢您的回复,此解决方案可行,但我想插入新数据而不必缓冲将被覆盖的旧数据。我知道这似乎是一个不必要的限制,但我正在处理的问题需要编辑大文件。这在记忆中会很麻烦。
    • 您不需要缓冲整个文件。 FWIW,上面的示例仅使用与您要输出的数据相同数量的缓冲区(并且与实际文件的大小无关)。
    猜你喜欢
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多