Feed data from file into Ring buffer efficiently - c

I have searched around on the internet and there were few document about how we use Ring Buffer to read from file or write to a file. So i wrote my own implementation here:
my ringbuffer structure
typedef struct Ringbuffer {
char* buffer;
int length;
int start;
int end;
int fd;
int looped;
} RingBuffer;
//to update the end of the buffer after writing
#define RingBuffer_commit_write(B, A) (B)->end += A;if((B)->end >=(B)->length){(B)->looped =1;(B)->end %= (B)->length;}
#define RingBuffer_ends_at(B) ((B)->buffer + (B)->end)
static inline int RingBuffer_available_space(RingBuffer *buffer) {
return buffer->length- RingBuffer_available_data(buffer);
}
code snippet to read from file
void read_some(int sockfd,RingBuffer *buffer) {
int byte_recv =0;
check((RingBuffer_available_space(buffer) > 0),"out of space, release some data");
if(buffer->looped == 0){
byte_recv = recv(sockfd,buffer,buffer->length - buffer->end,0);
if(byte_recv < buffer->length- buffer->end){
RingBuffer_commit_write(buffer,byte_recv);
return ;
}else{
RingBuffer_commit_write(buffer,byte_recv);
byte_recv = recv(sockfd,buffer,RingBuffer_ends_at(buffer),RingBuffer_available_space(buffer),0);
RingBuffer_commit_write(buffer,byte_recv);
}
}else{
byte_recv = recv(sockfd,buffer,RingBuffer_available_space(),0);
RingBuffer_commit_write(buffer,byte_recv)
}
error:
return;
}
This, however, is not efficient and overcomplicated in my opinion. Is there a better implementation of Ring buffer to read from file( since both socket and file are quite the same)? Any help,even an idea only,would be appreciated.

Related

Send message through Ring (Circular) Buffer between Threads (in C)

I need to send a message from Main thread to my Created Thread using WinAPI and Ring Buffer.
I defined structures and wrote functions for my Ring buffer.
Ring Buffer - it contains head, tail, size and pointer to the structure Descriptor which has length of Data and data itself. As I need to send 2 parameters to CreateThread function, I created the third structure ThreadParams to keep 2 parameters.
I want to leave this structures how they are now, not changeable.
typedef struct _Descriptor
{
uint32_t dataLen;
void * data;
} Descriptor;
typedef struct _ringBuffer
{
Descriptor *bufferData;
int head;
int tail;
int size;
} ringBuffer;
typedef struct _ThreadParams
{
void * ptr1;
void * ptr2;
} ThreadParams;
There are my realisations of Ring Buffer functions:
void bufferFree(ringBuffer *buffer)
{
free(buffer->bufferData);
}
void ringInitialization(ringBuffer *buffer, int size)
{
buffer->size = size;
buffer->head = 0;
buffer->tail = 0;
buffer->bufferData = (Descriptor*)malloc(sizeof(Descriptor) * size);
}
int pushBack(ringBuffer *buffer, void * data) // fill buffer
{
buffer->bufferData[buffer->tail++] = *(Descriptor*)data;
if (buffer->tail == buffer->size)
{
buffer->tail = 0;
}
return 0;
}
int popFront(ringBuffer *buffer)
{
if (buffer->head != buffer->tail)
{
buffer->head++;
if (buffer->head == buffer->size)
{
buffer->head = 0;
}
}
return 0;
}
My main: I checked that I can send a few bytes (the memory is shared between threads), now I need to send a big message (> BUFF_SIZE) though Ring Buffer what I'm trying to do in while() cycle. Here is the question: how should I do it? My thing doesn't work because I catch an exception in printf() function (memory acces violation).
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <strsafe.h>
#include <stdint.h>
#define RING_SIZE 256
#define BUFFER_SIZE 1024
DWORD WINAPI HandleSendThread(LPVOID params);
uint8_t * getPointer(uint8_t *buffer, uint32_t index)
{
uint8_t * ptr = ((uint8_t*)buffer) + index * BUFFER_SIZE;
return ptr;
}
int main(int argc, char * argv[])
{
//Descriptor * ringData = (Descriptor *)malloc(sizeof(Descriptor) * RING_SIZE);
ringBuffer ring;
ringInitialization(&ring, RING_SIZE);
void * packetBuffer = malloc(BUFFER_SIZE * RING_SIZE);
uint8_t * currentBuffer = getPointer(packetBuffer, 0);
uint8_t * str = "Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you'd expect to be involved in anything strange or mysterious, because they just didn't hold with such nonsense. Mr.Dursley was the director of a firm called Grunnings, which made drills.He was a big, beefy man with hardly any neck, although he did have a very large mustache.Mrs.Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors.The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.";
strcpy(currentBuffer, str);
ring.bufferData[0].data = currentBuffer;
ring.bufferData[0].dataLen = strlen(str);
int currentSize = 0;
int ringSize = RING_SIZE;
while(ring.bufferData[0].data != '\0')
{
for (int i = currentSize; i < ringSize; i + RING_SIZE)
{
pushBack(&ring, currentBuffer);
printf("h = %s, tail = %s, dataBuffer = %s\n", (char*)ring.head, (char*)ring.tail, (char*)ring.bufferData[i].data);
}
currentSize = ringSize;
ringSize = 2 * ringSize;
popFront(&ring);
}
ThreadParams params = { &ring, packetBuffer };
HANDLE MessageThread = 0;
MessageThread = CreateThread(NULL, 0, HandleSendThread, &params, 0, NULL);
if (MessageThread == NULL)
{
ExitProcess(MessageThread);
}
WaitForSingleObject(MessageThread, INFINITE);
CloseHandle(MessageThread);
system("pause");
return 0;
}
And my CreateThread function:
DWORD WINAPI HandleSendThread(LPVOID params)
{
ringBuffer * ring = ((ThreadParams*)params)->ptr1;
void * buffer = ((ThreadParams*)params)->ptr2;
//ring->bufferData[0].dataLen = sizeof(buffer) + sizeof(ring->bufferData[0])*1024;
printf("Shared memory check: ringBuffer data = \"%s\", \nlength = %d\n", (char*)ring->bufferData[0].data, ring->bufferData[0].dataLen);
return 0;
}
Your most immediate problem is the inconsistency between the code in pushBack(), which expects data to point to a Descriptor, and the code in your main function, which passes in a pointer to a string instead.
If you had declared pushBack() properly, i.e.,
void pushBack(ringBuffer *buffer, Descriptor * data)
{
buffer->bufferData[buffer->tail++] = *data;
if (buffer->tail == buffer->size)
{
buffer->tail = 0;
}
}
Then the compiler would have been able to warn you about the discrepancy.
You also have an infinite loop here:
for (int i = currentSize; i < ringSize; i + RING_SIZE)
You probably meant
for (int i = currentSize; i < ringSize; i += RING_SIZE)
... although it still doesn't look to me like it will do anything sensible. Nor do I understand the purpose of the outer loop, which compares a pointer to a character.
Found a solution
int main(int argc, char * argv[])
{
ringBuffer ring;
ringInitialization(&ring, RING_SIZE);
void * packetBuffer = malloc(BUFFER_SIZE * RING_SIZE);
Descriptor temp = { 0 };
uint8_t * currentBuffer = getPointer(packetBuffer, 0);
uint8_t * str = "Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you'd expect to be involved in anything strange or mysterious, because they just didn't hold with such nonsense. Mr.Dursley was the director of a firm called Grunnings, which made drills.He was a big, beefy man with hardly any neck, although he did have a very large mustache.Mrs.Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors.The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.";
strcpy(currentBuffer, str);
temp.dataLen = strlen(str);
temp.data = currentBuffer;
pushBack(&ring, &temp);
ThreadParams params = { &ring, packetBuffer };
HANDLE MessageThread = 0;
MessageThread = CreateThread(NULL, 0, HandleSendThread, &params, 0, NULL);
if (MessageThread == NULL)
{
ExitProcess(MessageThread);
}
WaitForSingleObject(MessageThread, INFINITE);
CloseHandle(MessageThread);
system("pause");
return 0;
}
DWORD WINAPI HandleSendThread(LPVOID params)
{
ringBuffer * ring = ((ThreadParams*)params)->ptr1;
void * buffer = ((ThreadParams*)params)->ptr2;
Descriptor * temp = &ring->bufferData[ring->head];
for (int i = 0; i < temp->dataLen; i++)
{
printf("%c", ((char*)temp->data)[i]);
}
printf("\n");
return 0;
}

Data exchange between Server and Client with Ring Buffer (Circular Buffer) in C

I wrote client-server chat for multiple clients (multiplexing i/o with non-blocking sockets).
Now I have fixed bufferSize (for example, length = 64).
I want to make data exchange between client and server with Ring Buffer. I also wrote a few functions (buffer inisialisation, popFront and pushBack) to write into a buffer.
How is it possible to realize this idea? For example, I suppose I need 2 structures: the first structure has bufferlength and pointer to data in the other buffer, the second buffer has data. But now I have no idea what I should do with it. Could you give me an advice and maybe show with code? Thanks.
Here are my ringBuffer structures and function (I suppose the function bufferSize is wrong):
struct ringBuffer
{
int *bufferData;
int head;
int tail;
int size;
};
void bufferFree(struct ringBuffer *buffer)
{
free(buffer->bufferData);
}
void bufferInitialization(struct ringBuffer *buffer, int size)
{
buffer->size = size;
buffer->head = 0;
buffer->tail = 0;
buffer->bufferData = (int*)malloc(sizeof(int) * size);
}
int pushBack(struct ringBuffer *buffer, int data)
{
buffer->bufferData[buffer->tail++] = data;
if (buffer->tail == buffer->size)
{
buffer->tail = 0;
}
return 0;
}
int popFront(struct ringBuffer *buffer)
{
if (buffer->head != buffer->tail)
{
buffer->head++;
if (buffer->head == buffer->size)
{
buffer->head = 0;
}
}
return 0;
}
int bufferSize(struct ringBuffer *buffer)
{
if (buffer->head >= buffer->tail)
{
return (buffer->head - buffer->tail);
}
else
{
return buffer->size - ((buffer->size - buffer->tail) + buffer->head);
}
/*for (int i = buffer->head; buffer->head < buffer->tail; i++)
{
printf("head[%d] and tail[%d] --> bufferData = %d", buffer->head, buffer->tail, buffer->bufferData);
}*/
return 0;
}
Basically, you need two things:
A shared ring of pointers between your clients and server.
A shared pool of buffers between your clients and server.
There are a variety of flavors for the ring buffer: lockless, multi-consumer, multi-producer etc.
Have a look at DPDK's ring library as an example or lockless rings. Here is a detailed description of algorithms:
http://dpdk.org/doc/guides/prog_guide/ring_lib.html
And here is the code:
http://dpdk.org/browse/dpdk/tree/lib/librte_ring

Can a char * or char ** masquerade as a FILE *?

In C, I often want to handle data read from a file and data read from an array of strings the same way. Usually reading from a file is for production and from strings is for testing. I wind up writing a lot of code like this:
void handle_line(char *line, Things *things) {
...
}
Things *read_from_chars(char *lines[]) {
Things *things = Things_new();
for (int i = 0; lines[i] != NULL; i++) {
handle_line(lines[i], things);
}
return things;
}
Things *read_from_input(FILE *input) {
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
while (getline(&line, &linelen, input) > 0) {
handle_line(line, things);
}
return things;
}
This is a duplication of effort.
Is there a way I can make an array of strings masquerade as a FILE * pointer? Or vice-versa? Or is there a better pattern for dealing with this problem?
For bonus points: the solution should make char * or char ** usable with the standard file functions like fgets and getline.
You could use a discriminated union that contains a FILE* and a pointer to the array, then write a get_next function that does the right thing with it.
typedef struct {
enum { is_file, is_array } type;
union {
FILE *file;
struct {
int index;
int size;
char **lines;
} array;
} data;
} file_or_array;
char *get_next(file_or_array foa) {
if (foa.type == is_file) {
char *line = NULL;
size_t linelen = 0;
getline(&line, &linelen, foa.data.file);
return line;
} else {
if (foa.data.array.index < foa.data.array.size) {
return strdup(foa.data.array.lines[foa.data.array.index++]);
} else {
return NULL;
}
}
}
The call to strdup() is necessary to make this work consistently. Since getline() returns a newly-allocated string, which the caller needs to free, it also does the same thing when returning a string from the array. Then the caller can safely free it in both cases.
There's a nonstandard function fmemopen that lets you open a char[] for reading or writing. It's available in most versions of GNU libc, I think, and most versions of Linux.
(This lets you read from or write to a single string, not the array of strings you asked about.)
One of the most powerful ways to handle this is via streams. I use them to hide file/string/serial ports etc
I have rolled my own stream library which I mainly use on embedded systems
the general idea is :-
typedef struct stream_s stream_t;
struct stream_s
{
BOOL (*write_n)(stream_t* stream, char* s, WORD n);
BOOL (*write_byte)(stream_t* stream, BYTE b);
BOOL (*can_write)(stream_t* stream);
BOOL (*can_read)(stream_t* stream);
BYTE (*read_byte)(stream_t* stream);
void* context;
};
then you make a whole bunch of functions
BOOL stream_create(stream_t* stream);
BOOL stream_write_n(stream_t* stream, char* s, WORD n);
BOOL stream_can_read(stream_t* stream);
BYTE stream_read_byte(stream_t* stream);
etc
that use those base function call backs.
the context in the stream struct you use to point to a struct for serial, string, file, or whatever you want. Then you have things like file_create_stream(stream_t* stream, char* filename) which will populate the callbacks on stream with the file related functions. Then for strings you have something similar but handles strings
There's more than one way to skin this particular cat, but in general the solution to this is hiding the implementation of the public interface behind an indirection which allows you to inject separate 'implementations'.
(This incarnation of your problem is also closely related to somewhat different problem of ensuring ABI compatibility between versions of code.)
To solve this in C you can do it similar to the pimpl with-inheritance in C++ (protected instead of private d-pointer, with overridden protected constructors):
You create an opaque 'reader'/'stream' object (pointer to forward declared struct w/ typedef in C) and suitably named constructor functions to instantiate the opaque object which inject the desired implementation.
Let's sketch out example header files to give you an idea of how the functions fit together. Let's start with the guts, the definition of the d-pointer/p-impl objects (N.B.: I'm omitting some boilerplate like header guards):
reader-private.h:
/* probably should be in its proper C file, but here for clarification */
struct FileReaderPrivateData {
FILE * fp;
};
/* probably should be in its proper C file, but here for clarification */
struct StringReaderPrivateData {
size_t nlines;
size_t cursor;
char ** lines;
};
/* in C we don't have inheritance, but we can 'fix' it using callbacks */
struct ReaderPrivate {
int (* close)(void* pData); /* impl callback */
ssize_t (* readLine)(void* pData, char** into); /* impl callback */
/* impl-specific data object, callbacks can type cast safely */
void * data;
};
/* works like a plain p-impl/d-pointer, delegates to the callbacks */
struct Reader {
struct ReaderPrivate * dPtr;
}
reader.h:
typedef struct Reader* Reader;
/* N.B.: buf would be a pointer to set to a newly allocated line buffer. */
ssize_t readLine(Reader r, char ** buf);
int close(Reader r);
file-reader.h
#include "reader.h"
Reader createFileReader(FILE * fp);
Reader createFileReader(const char* path);
string-reader.h
#include "reader.h"
Reader createStringReader(const char**, size_t nlines);
That's a general pattern for doing pimpl/d-pointer with inheritance in C, so you can abstract the implementation guts behind a public interface which is accessed through opaque pointers. This mechanism is generally useful to guarantee API and ABI compatibility between various implementations of the public interface and to implement a simple inheritance pattern.
Here's an implementation using fcookieopen [IIRC, BSD has something similar]:
// control for string list
struct cookie {
char **cook_list; // list of strings
int cook_maxcount; // maximum number of strings
int cook_curidx; // current index into cook_list
int cook_curoff; // current offset within item
};
int cookie_close(void *vp);
ssize_t cookie_read(void *vp,char *buf,size_t size);
cookie_io_functions_t cook_funcs = {
.read = cookie_open;
.close = cookie_close;
};
// cookie_open -- open stream
FILE *
cookie_open(char **strlist,int count,const char *mode)
// strlist -- list of strings
// count -- number of elements in strlist
// mode -- file open mode
{
cookie *cook;
FILE *stream;
cook = calloc(1,sizeof(cookie));
cook->cook_list = strlist;
cook->cook_maxcount = count;
stream = fopencookie(cook,mode,&cook_funcs);
return stream;
}
// cookie_close -- close stream
int
cookie_close(void *vp)
{
free(vp);
return 0;
}
// cookie_read -- read stream
ssize_t
cookie_read(void *vp,char *buf,size_t size)
{
cookie *cook = vp;
char *base;
ssize_t totcnt;
totcnt = 0;
while (size > 0) {
// bug out if all strings exhausted
if (cook->cook_curidx >= cook->cook_maxcount)
break;
base = cook->cook_list[cook->cook_curidx];
base += cook->cook_curoff;
// if at end of current string, start on the next one
if (*base == 0) {
cook->cook_curidx += 1;
cook->cook_curoff = 0;
continue;
}
// store character and bump buffer and count
*buf++ = *base;
size -= 1;
totcnt += 1;
cook->cook_curoff += 1;
}
return totcnt;
}
If you need this functionality just for debugging, write a fopen_strings(char *list[]) function to:
create a temporary file
open that with fopen with mode "r+"
write all your strings into it
delete the file (the FILE* can still operate on it, until it is closed either explicitly or implicitly at program end. You might need to skip this step on some operating systems that prevent deletion of open files.
rewind the stream
return the stream and let your program use it as it would a regular file.
is there a better pattern for dealing with this problem?
My proposed solution is to do function overloading.
Provide all possible parameters:
Things* readThings(FILE *f, char *l[])
{
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
if (f)
{
while(getline(&line, &linelen, input) > 0)
handle_line(line, things);
}
else
{
for(int i = 0; lines[i] != NULL; i++)
handle_line(lines[i], things);
}
return things;
}
Things* readThingsChar(char *l[]){ return readThings(0, l); }
Things* readThingsFile(FILE *f){ return readThings(f, 0); }
How to use
FILE *f;
char *l[100];
..
Things *a = readThings(f,0); // or readThingsFile(f)
Things *b = readThings(0,l); // or readThingsChar(l)
You could embed it in the data:
Things* readThings(char *l[])
{
char *line = NULL;
size_t linelen = 0;
Things *things = Things_new();
FILE *f = NULL;
if (l[0][0]==UNIQUE_IDENTIFIER)
{
f = fopen(l[0]+1);
while(getline(&line, &linelen, input) > 0)
handle_line(line, things);
fclose(f);
}
else
{
for(int i = 0; lines[i] != NULL; i++)
handle_line(lines[i], things);
}
return things;
}
How to use
char *f[1] = { "_file.txt" };
char *l[100] = { "first line", .. "last line" };
f[0][0] = UNIQUE_IDENTIFIER;
Things *a = readThings(f);
Things *b = readThings(l);

Read a char string as a virtual file

The question may seems strange but I didn't misspelled it:
I want to decompress some data I downloaded without write them on the HDD. For that, I download it in a dynamically allocated buffer and I'd like to send it to the zlib wrapper I use (miniunzip). The problem is that this implementation is quite long (2-3K lines) and I'd like to avoid to have to rewrite it just for few lines.
I'd like to know if there was any way to read the buffer via a FILE* structure (miniunzip use it's own structure but I found a "fopen()" hiden under the loader). I know its length if it can help.
Thanks in advance and excuse me for my poor grammar.
I'm working on both Windows and UNIX systems (OSX/GNU Linux).
If you're talking about the minizip library that's included with zlib, you could use the unzOpen2 function which allows you to specify a structure containing the I/O functions to use. This should get you started:
struct zmem_data {
char *buf;
size_t length;
};
static voidpf zmemopen(voidpf opaque, const char *filename, int mode) {
if ((mode&ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) return NULL;
uLong *pos = malloc(sizeof(uLong));
*pos = 0;
return pos;
}
static uLong zmemread(voidpf opaque, voidpf stream, void* buf, uLong size) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
uLong remaining = data->length - *pos;
uLong readlength = size < remaining ? size : remaining;
if (*pos > data->length) return 0;
memcpy(buf, data->buf+*pos, readlength);
*pos += readlength;
return readlength;
}
static uLong zmemwrite(voidpf opaque, voidpf stream, const void *buf, uLong size) {
/* no write support for now */
return 0;
}
static int zmemclose(voidpf opaque, voidpf stream) {
free(stream);
return 0;
}
static int zmemerror(voidpf opaque, voidpf stream) {
if (stream == NULL) return 1;
else return 0;
}
static long zmemtell(voidpf opaque, voidpf stream) {
return *(uLong*)stream;
}
static long zmemseek(voidpf opaque, voidpf stream, uLong offset, int origin) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_SET:
*pos = offset;
break;
case ZLIB_FILEFUNC_SEEK_CUR:
*pos = *pos + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
*pos = data->length + offset;
break;
default:
return -1;
}
return 0;
}
static void init_zmemfile(zlib_filefunc_def *inst, char *buf, size_t length) {
struct zmem_data *data = malloc(sizeof(struct zmem_data));
data->buf = buf;
data->length = length;
inst->opaque = data;
inst->zopen_file = zmemopen;
inst->zread_file = zmemread;
inst->zwrite_file = zmemwrite;
inst->ztell_file = zmemtell;
inst->zseek_file = zmemseek;
inst->zclose_file = zmemclose;
inst->zerror_file = zmemerror;
}
static void destroy_zmemfile(zlib_filefunc_def *inst) {
free(inst->opaque);
inst->opaque = NULL;
}
void example() {
zlib_filefunc_dec fileops;
init_zmemfile(&fileops, buffer, buffer_length);
unzFile zf = unzOpen2(NULL, &fileops);
/* ... process zip file ... */
unzClose(zf);
destroy_zmemfile(&fileops);
}
To summarize your question: You want to provide a FILE* interface for an in-memory buffer. No, you can't do that. The fread(), etc. calls actually end up making system calls that deal with an open file descriptor which you don't have.
You're over-complicating this. Decompression code almost always works from buffers that are in memory. If they have a file interface, certainly that is just a wrapper which handles reading the file into memory and then decompressing (probably in chunks to save memory). You should be able to find a decompression library with calls to decompress a buffer that you give it (just a pointer and a length).
Why you don't want to write the downloaded data to the hard drive is certainly up to you, but I hope this is for good, and not for evil.
The other option would be to open a memory-mapped file, to which you write during download, and read during decompression. There may be a way to specify that the file not be written to disk but of that I am unsure. Also, this would be very different between windows and linux.
These may help:
File Mapping (Windows)
mmap (POSIX)

Manage data inside a buffer

I'm using this code to read a file into a buffer. The file is full of structs of evaluacion type (including some char and int variables).
Now I have the whole file in a buffer, how can I find the values of one variable in the buffer now?
For example buf.notamedia < 4. There are supposed to be many of them inside the file.
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes = 1;
int nbytese = 0;
evaluacion buf;
struct stat datos;
fstat(fd, &datos);
printf("Size of file = %d \n", datos.st_size);
char *buffer = (char *)malloc(datos.st_size);
int actual = read(fd, buffer, datos.st_size);
printf("actual = %d\n", actual);
if (buf.notamedia >= 4.5 && buf.notamedia < 5)
{
/* ... */
}
}
Any idea is very welcome
I'm doing as you said, but I'm only getting one iteration, I don't know what I'm doing wrong :(
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
printf("Number of structs = %d", (datos.st_size/(sizeof(evaluacion))));
for (i=0;i<(datos.st_size/(sizeof(evaluacion)));i++);
{
printf("Notamedia = %f\n",buffer[i].notamedia);
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
printf("Notamedia = %f\n",buffer[i].notamedia);
}
{
}
}
}
Easiest to define the buffer as a pointer to the data structure and use that to dereference the data (although you should ensure the file size is a multiple of the structure size).
i.e.
evaluacion* buffer = (evaluation*)malloc(datos.st_size);
if(buffer[0].notamedia >= 4.5)
You can then increment the index to access other structures you loaded.
Thanks for the comments, I think I solved the problem, I modified the code:
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes=1;
int nbytese=0;
int i=0;
int n=0;
struct stat datos;
fstat(fd, &datos);
evaluacion buf;
printf("File size = %d \n", datos.st_size);
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
do
{
i++;
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
n=n+1;
/*printf("Notamedia = %f\n",buffer[i].notamedia);
*/
buffer[i].notamedia=5;
}
}while (i<(datos.st_size/(sizeof(evaluacion))));
nbytese=write(fd,buffer,datos.st_size);
printf("Written bytes = %d\n",nbytese);
return(n);
}
Now, If the condition is matched, I'm modifying the buffer. Once I read all the structs I write the file in the disk again, but I still have a problem, every time, instead of write the file in the same position, seems like I'm adding the same information after the old one, so if I read the file once I get 3.5Mb, two times 7MB and so on :S.
Any idea what can I do?
Thanks

Resources