Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
191 views
in Technique[技术] by (71.8m points)

c - Writing to file using setvbuf, conditionally discard buffer contents

I would like to write a simple API which

  1. allows the user to open a file.
  2. let the user write data to the file
  3. track the write calls and sanity check the written data after each write call.
  4. prevents the data from beeing written to disk if it is not valid -> discard(file)

As a starting point i wrote the test program below, which opens a file in fully buffered "rb+" mode using fopen and setvbuf. The stream is opened in fully buffered mode for the following reason:

http://www.cplusplus.com/reference/cstdio/setvbuf/

mode Specifies a mode for file buffering.

Three special macro constants [...]:

_IOFBF Full buffering: On output, data is written once the buffer is full (or flushed). On Input, the buffer is filled when an input operation is requested and the buffer is empty.

My testprogram contains comments where a validity check could be placed and where the buffer contents should be discarded.

My question is how do i accomplish the discard(file) operation which means the step of getting rid of invalid buffer contents ?

The idea behind this is to assemble some data in the buffer, do a regular validity check after each or several write operations and write the data to disk only, if the data is valid. Therefore i would need to discard the buffer, if the validity check fails. When the validity check passes, the whole buffer contents should be written to the file.

My code draft looks like in the following. This is a simplified example:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

int main(void)
{
    static uint8_t buffer[10000];
    
    /* The following would be part of mylib_init */
    FILE *file = fopen("test", "wb+");
    
    if (file == NULL){
        print ("open error!");
        exit(-1);
    }
    
    if ( 0 != setvbuf(file , buffer, _IOFBF , sizeof(buffer) ) ){
        print("Could not set buffer!");
        fclose(file);
        exit (-2);
    }
    
    /* The following would be part of mylib_write_data.
       Each write and check resembles one func call */

    // Pretend the user writes some data into the file
    // ...
    // fwrite(x)
    
    if (data_in_buffer_not_valid(buffer)){
       discard(file);
    }

    // ...
    // fwrite(y)
    //

    if (data_in_buffer_not_valid(buffer)){
       discard(file);
    }

    // ...
    // fwrite(z)
    // ...
    
         
    // The following would be part of mylib_exit
    // Cleanup stuff
    fclose(file)

    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you want to have some like "scratch" temporary file that you want to write your data into and then retrieve them later, then the portable interface would be tmpfile() - it's an interface created just for that. Write to that file, rewind if you want, and when you're ready, rewind it and read from it block by block to another file.

On linux you may use fmemopen and fopencookie to write to a buffer via FILE* - these functions are not available on windows.

I would also strongly consider just creating your own interface that would store the result in memory. Writing an interface like struct mystream; mystream_init(struct mystream *); mystream_printf(struct mystream *, const char *fmt, ...); etc. is some of the tasks you sometimes do in C when fopencookie is not available. And consider writing the interface for storing data, so that instead of calling fwrite you would actually call the function that would check the data and write them and process them along the way.

As for setvbuf, note the standard. From C11 7.21.3p3:

When a stream is unbuffered, characters are intended to appear from the source or at the destination as soon as possible. Otherwise characters may be accumulated and transmitted to or from the host environment as a block. When a stream is fully buffered, [...]. When a stream is line buffered, [...] Support for these characteristics is implementation-defined, and may be affected via the setbuf and setvbuf functions.

And these buffering modes may just be not supported at all. And from C11 7.21.5.6:

The setvbuf function may be used only after the stream pointed to by stream has been associated with an open file and before any other operation (other than an unsuccessful call to setvbuf) is performed on the stream. [...] The contents of the array at any time are indeterminate.

You can't count on anything what will be the content of the buffer. Do not expecting any data there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...