How to read a binary file and save it inside a pipe - c

I used the code below to open a binary file fp (the file contain a saved 2D array) and put it inside a pipe:
if ((fp=fopen("file", "rb"))==NULL) {
printf("Cannot open file.\n");
}
if (fread(array, sizeof(int), 5*5, fp) != 5*5) {
if (feof(fp))
printf("Premature end of file.");
} else {
printf("File read error fread.");
}
Is this the code to put it inside the pipe?
close(fd[0]);
if ((ch=fgetc(fp))==EOF)
write(fd[1], &ch, 1 );
If I want to make a sum of the array, how could I make it?

The most sensible way to write the array to the pipe, as long as the size remains small, is to do:
int nw = 5 * 5 * sizeof(int);
if (write(fd[1], array, nw) != nw)
err_exit("Failed to write to pipe");
(Where err_exit() is a function that writes a message to standard error and exits (or does not return.)
This assumes that your array is a 5x5 array (a comment from you implies it is 10x2, in which case your reading code has major problems). It assumes that the size of the buffer in a pipe is big enough to hold the data; if it is not, your write call may block. It assumes that there is somewhere a process to read from the pipe; if this is the only process, the write() will trigger a SIGPIPE signal, killing your process, because of the close(fd[0]);.
Writing one byte at a time is possible - it is not stellar for performance.
Reading one byte at a time from fp after you've already read the data into array is not entirely sensible - you are at best reading different data for writing to the pipe.
The normal way of summing a 2D array is (C99):
enum { DIM_1 = 5, DIM_2 = 5 };
int array[DIM_1][DIM_2];
...data to load array...
int sum = 0;
for (int i = 0; i < DIM_1; i++)
{
for (int j = 0; j < DIM_2; j++)
sum += array[i][j];
}
It doesn't matter where the data came from, just so long as you actually initialized it.

Related

Sort a binary file with qsort

EDIT 3
THE FILE CONTAINS BYTES - I guess I have to sort the bytes, the task doesn't say more - it says that I pass an argument - the name of a binary file that contains bytes - that's it. And I am trying to work with low-level funcs.
I am trying to sort a binary file using qsort but I got stuck - I dont know how to write the content of a file to a buffer so I could pass it to qsort
What I have done:
int main(int argc, char*argv[]){
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
int size;
char c;
while(read(fd1, &c, 1)){
size=size+1;
}
size=size+1;
close(fd1);
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occured while opening the file");
}
char*buffer;
buffer=malloc(size);
setbuf(fd1, buffer);
//EDIT I TRIED THIS AND IT STILL DOES NOT WORK
int i=0;
while(read(fd1, &c, 1)){
buffer[i]=c;
i++;
}
for(int i=0; i<size;i++){
printf("lele %s", buffer[i]);
}
//EDIT 2: after making buffer[i]=c I get this error Segmentation fault
}
SetBuf does not work this way.. How to make it work? Also, I am trying to use func like open, close, read, write, etc.
Your algorithm for reading a file into a buffer is good:
Open the file
Count bytes in file
Close the file
Allocate the buffer
Open the file
Read the file
Close the file
A bit inefficient, because you read the file twice, but that's fine. You just have to implement it properly; any small mistake will make it look like it doesn't work. Use a debugger to check each step.
Here is my try. I didn't debug, to not deny you the "fun" of debugging. I put comments instead.
int main(int argc, char*argv[])
{
// 1. Open the file
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
// 2. Count bytes in file
int size = 0;
char c;
while(read(fd1, &c, 1))
size=size+1;
// To check that this part is good, print the size here!
// 3. Close the file
close(fd1);
// Allocate the buffer
char *buffer;
buffer = malloc(size);
// Might want to print the buffer here, to make sure it's not NULL
// 5. Open the file
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occurred while opening the file");
}
// 6. Read the file
for (int index = 0; index < size; ++index)
read(fd1, &buffer[index], 1);
// Might want to print what "read" returns in each iteration, to make sure it's successful
// 7. Close the file
close(fd1);
}
As noted by Eric Postpischil, the algorithm is actually not good.
The size of the file at one time does not guarantee the size at another time.
If you want to do that correctly, you must read the file only once. This will make the allocation harder: you cannot calculate the required buffer size, so you have to "guess" an initial size and use realloc.
However, in this small example, this is clearly not the requirement - you can probably ignore the possibility of the file changing asynchronously.
There is another possible problem - I/O error on the file when you read it the second time. This is easy to check, so maybe you should add it.

Two processes writing on the same file

I know this is recipe for disaster. And I actually made it work using shared variables.
But it's homework, and teacher definitely wants us to put many processes writing to the same file using different file pointers. I've been trying all day with little success, but I just can't find why this fails.
I have approached the problem in the folowing way:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int status;
int process_count = 0;
do
{
int from = (n / np) * (process_count) + 1;
int to = (n / np) * (process_count + 1);
if (fork() == 0)
{
FILE *aux;
aux = fopen("./parciais.txt", "w");
fseek(aux, sizeof(int) * process_count, SEEK_SET);
int sum = 0;
int i = from;
while (i <= to)
{
int square = i * i;
sum += square;
i++;
}
long int where_am_i = ftell(aux);
printf("I am process %i writing %i on byte: %li\n", process_count, sum, where_am_i);
fwrite(&sum, sizeof(int), 1, aux);
fclose(aux);
exit(1);
}
else
{
wait(&status);
process_count++;
}
} while (process_count < np);
FILE *aux;
aux = fopen("./parciais.txt", "r");
int sum;
for (int i = 0; i <= np - 1; i++)
{
fseek(aux, sizeof(int) * i, SEEK_SET);
long int where_am_i = ftell(aux);
int read;
fread(&read, sizeof(int), 1, aux);
printf("I am reading %i at byte: %li\n", read, where_am_i);
sum += read;
}
}
I expected the output to be something such as:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 98021 at byte: 0
I am reading 677369 at byte: 4
I am reading 1911310 at byte: 8
But I get:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 0 at byte: 0
I am reading 0 at byte: 4
I am reading 1911310 at byte: 8
This means, for some reason, only the last value is written.
I've been banging my head on the wall over this and I just can't find where's the catch... Can someone please lend me a hand?
The problem is due to fopen("./parciais.txt", "w") :
"w" : "Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file."
Try with "a" instead!
("Appends to a file. Writing operations, append data at the end of the file. The file is created if it does not exist.")
As mentioned in another answer, the "a" argument is not enough either. The file must be created once, hence in the main process, and then accessed in "r+b" mode for the fseek to work correctly!
As #B.Go already answered, the main problem is that you are opening the file with mode "w", which truncates it to zero length if it already exists. Each child process does this, clobbering the contents written by the previous one.
You want this combination of behaviors for the file:
it is created if it does not already exist (or I suppose you want this, at least)
it is not truncated upon opening if it does already exist
you may write to it
writes start at the current file offset, as opposed to automatically going to the current end of the file
the file is binary, not subject to any kind of character translation or to tail truncation upon writing to it
Unfortunately, there is no standard mode that provides all of it: the various r modes require that the file already exist, the w modes truncate the file if it does already exist, and the a modes direct all writes to the current end of the file, regardless of the stream's current offset. If you can assume that the file will already exist then mode "r+b", which can also be spelled "rb+", has all the wanted characteristics except creating the file if it doesn't exist:
aux = fopen("./parciais.txt", "r+b");
That permits reading as well, but just because you can read from the file doesn't mean you have to do. Additionally, on Linux and POSIX-conforming systems, there is no distinction between binary and text files, so you can omit the b if you are confident that your program needs to run only on POSIX systems. That you are using fork() suggests that this condition may apply to you.
If you must provide for creating the file, too, then open it once at the very beginning of the program, using any of the w or a modes depending on whether you want to truncate the file, then immediately close it again:
FILE *aux = fopen("./parciais.txt", "a");
if (aux) {
fclose(aux);
} else {
// handle error ...
}

Getting characters past a certain point in a file in C

I want to take all characters past location 900 from a file called WWW, and put all of these in an array:
//Keep track of all characters past position 900 in WWW.
int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
printf("%d \n", Seek900InWWW);
if(Seek900InWWW < 0)
printf("Error seeking to position 900 in WWW.txt");
char EverythingPast900[appropriatesize];
int NextRead;
char NextChar[1];
int i = 0;
while((NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
EverythingPast900[i] = NextChar[0];
printf("%c \n", NextChar[0]);
i++;
}
I try to create a char array of length 1, since the read system call requires a pointer, I cannot use a regular char. The above code does not work. In fact, it does not print any characters to the terminal as expected by the loop. I think my logic is correct, but perhaps a misunderstanding of whats going on behind the scenes is what is making this hard for me. Or maybe i missed something simple (hope not).
If you already know how many bytes to read (e.g. in appropriatesize) then just read in that many bytes at once, rather than reading in bytes one at a time.
char everythingPast900[appropriatesize];
ssize_t bytesRead = read(WWW, everythingPast900, sizeof everythingPast900);
if (bytesRead > 0 && bytesRead != appropriatesize)
{
// only everythingPast900[0] to everythingPast900[bytesRead - 1] is valid
}
I made a test version of your code and added bits you left out. Why did you leave them out?
I also made a file named www.txt that has a hundred lines of "This is a test line." in it.
And I found a potential problem, depending on how big your appropriatesize value is and how big the file is. If you write past the end of EverythingPast900 it is possible for you to kill your program and crash it before you ever produce any output to display. That might happen on Windows where stdout may not be line buffered depending on which libraries you used.
See the MSDN setvbuf page, in particular "For some systems, this provides line buffering. However, for Win32, the behavior is the same as _IOFBF - Full Buffering."
This seems to work:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int WWW = open("www.txt", O_RDONLY);
if(WWW < 0)
printf("Error opening www.txt\n");
//Keep track of all characters past position 900 in WWW.
int Seek900InWWW = lseek(WWW, 900, 0); //goes to position 900 in WWW
printf("%d \n", Seek900InWWW);
if(Seek900InWWW < 0)
printf("Error seeking to position 900 in WWW.txt");
int appropriatesize = 1000;
char EverythingPast900[appropriatesize];
int NextRead;
char NextChar[1];
int i = 0;
while(i < appropriatesize && (NextRead = read(WWW, NextChar, sizeof(NextChar))) > 0) {
EverythingPast900[i] = NextChar[0];
printf("%c \n", NextChar[0]);
i++;
}
return 0;
}
As stated in another answer, read more than one byte. The theory behind "buffers" is to reduce the amount of read/write operations due to how slow disk I/O (or network I/O) is compared to memory speed and CPU speed. Look at it as if it is code and consider which is faster: adding 1 to the file size N times and writing N bytes individually, or adding N to the file size once and writing N bytes at once?
Another thing worth mentioning is the fact that read may read fewer than the number of bytes you requested, even if there is more to read. The answer written by #dreamlax illustrates this fact. If you want, you can use a loop to read as many bytes as possible, filling the buffer. Note that I used a function, but you can do the same thing in your main code:
#include <sys/types.h>
/* Read from a file descriptor, filling the buffer with the requested
* number of bytes. If the end-of-file is encountered, the number of
* bytes returned may be less than the requested number of bytes.
* On error, -1 is returned. See read(2) or read(3) for possible
* values of errno.
* Otherwise, the number of bytes read is returned.
*/
ssize_t
read_fill (int fd, char *readbuf, ssize_t nrequested)
{
ssize_t nread, nsum = 0;
while (nrequested > 0
&& (nread = read (fd, readbuf, nrequested)) > 0)
{
nsum += nread;
nrequested -= nread;
readbuf += nread;
}
return nsum;
}
Note that the buffer is not null-terminated as not all data is necessarily text. You can pass buffer_size - 1 as the requested number of bytes and use the return value to add a null terminator where necessary. This is useful primarily when interacting with functions that will expect a null-terminated string:
char readbuf[4096];
ssize_t n;
int fd;
fd = open ("WWW", O_RDONLY);
if (fd == -1)
{
perror ("unable to open WWW");
exit (1);
}
n = lseek (fd, 900, SEEK_SET);
if (n == -1)
{
fprintf (stderr,
"warning: seek operation failed: %s\n"
" reading 900 bytes instead\n",
strerror (errno));
n = read_fill (fd, readbuf, 900);
if (n < 900)
{
fprintf (stderr, "error: fewer than 900 bytes in file\n");
close (fd);
exit (1);
}
}
/* Read a file, printing its contents to the screen.
*
* Caveat:
* Not safe for UTF-8 or other variable-width/multibyte
* encodings since required bytes may get cut off.
*/
while ((n = read_fill (fd, readbuf, (ssize_t) sizeof readbuf - 1)) > 0)
{
readbuf[n] = 0;
printf ("Read\n****\n%s\n****\n", readbuf);
}
if (n == -1)
{
close (fd);
perror ("error reading from WWW");
exit (1);
}
close (fd);
I could also have avoided the null termination operation and filled all 4096 bytes of the buffer, electing to use the precision part of the format specifiers of printf in this case, changing the format specification from %s to %.4096s. However, this may not be feasible with unusually large buffers (perhaps allocated by malloc to avoid stack overflow) because the buffer size may not be representable with the int type.
Also, you can use a regular char just fine:
char c;
nread = read (fd, &c, 1);
Apparently you didn't know that the unary & operator gets the address of whatever variable is its operand, creating a value of type pointer-to-{typeof var}? Either way, it takes up the same amount of memory, but reading 1 byte at a time is something that normally isn't done as I've explained.
Mixing declarations and code is a no no. Also, no, that is not a valid declaration. C should complain about it along the lines of it being variably defined.
What you want is dynamically allocating the memory for your char buffer[]. You'll have to use pointers.
http://www.ontko.com/pub/rayo/cs35/pointers.html
Then read this one.
http://www.cprogramming.com/tutorial/c/lesson6.html
Then research a function called memcpy().
Enjoy.
Read through that guide, then you should be able to solve your problem in an entirely different way.
Psuedo code.
declare a buffer of char(pointer related)
allocate memory for said buffer(dynamic memory related)
Find location of where you want to start at
point to it(pointer related)
Figure out how much you want to store(technically a part of allocating memory^^^)
Use memcpy() to store what you want in the buffer

How to use poll() when dealing with multiple file descriptors?

I have a program that creates a number of input named pipes for which I must use poll() in order to watch over those pipes and get the information that has been written in them at the time that something has been written in them. I'm very new to polling and I couldn't find many examples that would clearly show how to use poll for multiple file descriptors.
Here is how I wrote the code:
char buffer [1024];
size_t count = 0;
ssize_t = bytes;
while(1)
{
int n = poll(pollFd, number_of_pipes, 3000);
if(n != 0)
{
if (n == -1)
{
perror("poll");
exit(1);
}
for(j = 0; j < number_of_pipes; j++)
{
if(pollFd[j].revents & POLLIN)
{
//read the written pipe
if((bytes = read(fd[j], buffer, sizeof(buffer))) > 0)
count += (size_t) bytes;
}
}
}
}
However, I'm not sure if this the correct way to handle the multiple input pipes while using poll(); since I'm also not sure how to know when the read function have reached the end of the file.
The code looks ok, if incomplete (you don't show how you set up the pollFd and fd arrays). It does ignore the actual data read, just counting the total amount; for a real program you probably want to do something with the data.
A couple of comments
If you change it to read from pollFd[j].fd instead of fd[j], you don't need the redundant fd array -- the descriptors are necessarily all in the pollFd array
You don't check for EOF or errors on read -- if read returns 0 or -1, you should remove that entry from the pollFd array and reduce number_of_pipes.

C program over-writing file contents in if statement

I have a C program that is trying to record something called an "avalanche size". The criteria for recording this is if the "delta_energy" which is generated by the program is less than equal to zero then I can increment my avalanche size by "*avalanche_size = *avalanche_size + 1;" and if the delta_energy is not less than equal to zero then it continues running the loop without incrementing the avalanche size.
So what I want to do is to write the delta energy WHEN THE AVALANCHE SIZE IS INCREMENTED (not otherwise) to a file called delta_energies_GSA as shown in the code below.
But I what I find to happen is that if I put the fprintf statement inside the if{ } where the avalanche size is incremented for sure, everytime it does one iteration, it over-writes all the entries in the file. So in the end I end up with the file containing only the delta energies for one of the iterations. If I take the fprintf statemenet and put it outside the bracket, it records everything but it also gives me the delta energies for when the avalanche size is not incremented and I don't want those.
I thought about doing maybe a condition like "if the avalanche size is bigger than the previous avalanche size then fprintf the delta energy" ... but I'm not sure how to do this since avalanche size is just an integer not a vector..
Any help would be really appreciated! Thank you
for (k = 0; k < n_nodes; k++)
{
if (delta_energy <= 0.0)
{
stored_state[i] = new_state;
*avalanche_size = *avalanche_size + 1;
printf("\n\n For k = %d: ",k);
printf("\n\n This is the delta energy with GSA for %d avalanche size:%f", *avalanche_size, delta_energy);
fprintf(delta_energies_GSA,"\n %d\t %d\t %f \n",k, *avalanche_size, delta_energy);
}
I haven't shown the full code because its a very large function of a very large program.
I have also been very careful about when I open and close the file. The file is opened right at the beginning of the function after I have declared my variables. And I close the file right before the function ends.
This is how the file is opened:
{
double d_energy, q_A_minus_1, one_over_q_A_minus_1, prob_term;
neighbor_inf *np;
extern int generate_new_state();
FILE *delta_energies_GSA;
delta_energies_GSA = fopen("delta_energies_GSA.dat", "w");
if (delta_energies_GSA == NULL)
{
printf("I couldn't open delta_energies_GSA.dat for writing.\n");
exit(0);
}
Right after declaring my variables and it is closed before the function ends:
fclose(delta_energies_GSA);
return(stored_state);
} /* end recover_stored_patterns_GSA() */
The fprintf() does exactly what you want to do, append a string to a file, I don't see anything wrong here with your code if the fopen() is outside the for loop (in this case use "w+" with fopen, for append) and there aren't seek to 0.
EDIT
My wrong, not "w+" but "a" for append (and if you don't need to also read the file).
The wrong behavior that you must investigate is "why the fprintf replace the whole file".
Try this simple test.
#include <stdio.h>
int main(int argc, char **argv) {
FILE *f = fopen("test", "w");
if (f) {
int i;
for (i=0; i<100; i++) {
if (i % 3)
fprintf(f, "%d\n", i);
}
fclose(f);
}
return 0;
}

Resources