C - Function read(file,buffer,bytes to read) breaking a string - c

I'm trying to read a file with 1024 lines with 9 times the same letter in each line and returning if it finds a line that doesn't match this terms.
The file is as follow but with 1024 lines:
eeeeeeeee
eeeeeeeee
eeeeeeeee
Code:
fd = open(fileName, O_RDONLY);
lseek(fd,0,SEEK_SET);
if(flock(fd, LOCK_SH) == -1)
perror("error on file lock");
if(fd != 0){
read(fd, lineFromFile, (sizeof(char)*10));
arguments->charRead = lineFromFile[0];
for(i=0; i < 1024; i++){
var = read(fd, toReadFromFile, (sizeof(char)*10));
if(strncmp(toReadFromFile,lineFromFile,10) != 0 || var < 10){
arguments->result = -1;
printf("%s \n\n",toReadFromFile);
printf("%s \n",lineFromFile);
printf("i %d var %d \n",i,var);
free(toReadFromFile);
free(lineFromFile);
return ;
}
}
}
Output:
> eeeee
eeee
eeeee
eeee
i 954 var 6
I have 5 different files with different letters and every single one gives this output in that specific line (954) and the line is correct with the letter writen 9 times with a \n in the end.
Any ideas why this could be happening? If i don't use the lseek it works fine but i need the lseek to divide the file in several parts to be tested by different threads. I put the 0 index in the lseek for simplification to show you guys.
Thanks.

It looks like you are looking for "eeeee\neeee" instead of "eeeeeeeee\n". Which means your file should should start like this:
eeeee
eeeeeeeee
eeeeeeeee
and end like this:
eeeeeeeee
eeee
If your file ends like this:
eeeeeeeee
eeeeeeeee
Then when you get to the last line, it will fail because you will only read "eeeee\n" instead of "eeeee\neeee".
Given the new information in your comment, I believe the problem is that you should not be seeking to the middle of lines (in this case 342 and 684). You should seek to an even multiple of the expected string (like 340 and 680). Also, line 954 is not where the problem happened. It should be line 954 + X, where X is the line you seeked to.

Whatever other problems your program may have, it certainly has this: the read() function is not guaranteed to read the full number of bytes requested. It will read at least one unless it encounters an error or the end of the file, and under many circumstances it does read the full number of bytes requested, but even when there are enough bytes remaining before the end of the file, read() may read fewer bytes than requested.
The comments urging you to use a higher-level function instead are well considered, but if you are for some reason obligated to use read() then you must watch for cases where fewer bytes are read than requested, and handle them by reading additional bytes into the unused tail end of the buffer. Possibly multiple times.
In function form, that might look like this:
int read_all(int fd, char buf[], int num_to_read) {
int total_read = 0;
int n_read = 0;
while (total_read < num_to_read) {
n_read = read(fd, buf + total_read, num_to_read - total_read);
if (n_read > 0) {
total_read += n_read;
} else {
break;
}
}
return (n_read < 0) ? n_read : total_read;
}

Related

My program creates a file named date.in but it is not inserting all the numbers

Write a C program that reads from the keyboard a natural number n
with up to 9 digits and creates the text file data.out containing the
number n and all its non-zero prefixes, in a single line, separated by
a space, in order decreasing in value. Example: for n = 10305 the data
file.out will contain the numbers: 10305 1030 103 10 1.
This is what I made:
#include <stdio.h>
int main()
{
int n;
FILE *fisier;
fisier=fopen("date.in","w");
printf("n= \n");
scanf("%d",&n);
fprintf(fisier,"%d",n);
while(n!=0)
{
fisier=fopen("date.in","r");
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
}
Few things:
Function calls may return error. You need to check that every time.
fisier=fopen("date.in","w");
This should have been followed by an error check. To understand more on what it return, first thing you should do is read the man page for that function. See man page for fopen(). If there is an error in opening the file, it will return NULL and errno is set to a value which indicates what error occurred.
if (NULL == fisier)
{
// Error handling code
;
}
Your next requirement is separating the numbers by a space. There isn't one. The following should do it.
fprintf(fisier, "%d ", n);
The next major problem is opening the file in a loop. Its like you are trying to open a door which is already open.
fisier=fopen("date.in","r");
if(NULL == fisier)
{
// Error handling code
;
}
while(n!=0)
{
n=n/10;
fprintf(fisier,"%d",n);
}
fclose(fisier);
A minor issue that you aren't checking is the number is not having more than 9 digits.
if(n > 999999999)
is apt after you get a number. If you want to deal with negative numbers as well, you can modify this condition the way you want.
In a nutshell, at least to start with, the program should be something similar to this:
#include <stdio.h>
// Need a buffer to read the file into it. 64 isn't a magic number.
// To print a 9 digit number followed by a white space and then a 8 digit number..
// and so on, you need little less than 64 bytes.
// I prefer keeping the memory aligned to multiples of 8.
char buffer[64];
int main(void)
{
size_t readBytes = 0;
int n = 0;
printf("\nEnter a number: ");
scanf("%d", &n);
// Open the file
FILE *pFile = fopen("date.in", "w+");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
while(n != 0)
{
// Append to the file
fprintf(pFile, "%d ", n);
n = n / 10;
}
// Done, close the file
fclose(pFile);
printf("\nPrinting the file: ");
// Open the file
pFile = fopen("date.in", "r");
if(NULL == pFile)
{
// Prefer perror() instead of printf() for priting errors
perror("\nError: ");
return 0;
}
// Read the file
while((readBytes = fread(buffer, 1, sizeof buffer, pFile)) > 0)
{
// Preferably better way to print the contents of the file on stdout!
fwrite(buffer, 1, readBytes, stdout);
}
printf("\nExiting..\n\n");
return 0;
}
Remember: The person reading your code may not be aware of all the requirements, so comments are necessary. Secondly, I understand english to a decent level but I don't know what 'fisier' means. Its recommended to name variables in such a way that its easy to understand the purpose of the variable. For example, pFile is a pointer to a file. p in the variable immediately gives an idea that its a pointer.
Hope this helps!
To draw a conclusion from all the comments:
fopen returns a file handle when successfull and NULL otherwise. Opening a file twice might result in an error (it does on my machine), such that fisier is set to NULL inside the loop. Obvioulsy fprintf to NULL wont do anything.
You only need to call fopen once, so remove it from the loop. After that it will work as intended.
It's alwas good to check if the fopen succeeded or not:
FILE *fisier;
fisier=fopen("date.in","w");
if(!fisier) { /* handle error */ }
You print no spaces between the numbers. Maybe that's intended, but maybe
fprintf(fisier,"%d ",n);
would be better.

Incorrect fprintf results

In the code below, I am trying to read from a socket and store the results in a file.
What actually happens, is that my client sends a GET request to my server for a file.html. My server finds the file and writes the contents of it to the socket. Lastly my client reads the content from thread_fd and recreates the file.
For some reason the recreated file has less content than the original. I have located the problem to be some lines in the end, that are missing. When I use printf("%s", buffer) inside the while loop everything seems fine in STDOUT but my fprintf misses somewhat 3.000 bytes for a file of 81.000 bytes size.
#define MAXSIZE 1000
int bytes_read, thread_fd;
char buffer[MAXSIZE];
FILE* new_file;
memset(buffer, 0, MAXSIZE);
if((new_file = fopen(path, "wb+")) == NULL)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
fprintf(new_file, "%s", buffer);
if(bytes_read < MAXSIZE)
break;
memset(buffer, 0, MAXSIZE);
}
You read binary data from the socket that may or may not contain a \0 byte. When you then fprintf that data the fprintf will stop at the first \0 it encounters. In your case that is 3000 bytes short of the full file. If your file contains no \0 byte the fprintf will simply continue printing the ram contents until it segfaults.
Use write() to write the data back to the file and check for errors. Don't forget to close() the file and check that for errors too.
Your code should/could look like:
int readfile(int thread_fd, char *path)
{
unsigned int bytes_read;
char buffer[MAXSIZE];
int new_file;
if ((new_file = open(path, _O_CREAT|_O_BINARY,_S_IWRITE)) == -1) return -1;
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
{
if (write(new_file, buffer, bytes_read)!= bytes_read) {
close(new_file);
return -2;
}
}
close(new_file);
return 0;
}
There are a few issues with your code that can cause this.
The most likely cause is this :
if(bytes_read < MAXSIZE)
break;
This ends the loop when read returns less than the requested amount of bytes. This is however perfectly normal behavior, and can happen eg. when not enough bytes are available at the time of the read call (it's reading from a network socket after all). Just let the loop continue as long as read returns a value > 0 (assuming the socket is a blocking socket - if not, you'll also have to check for EAGAIN and EWOULDBLOCK).
Additionally, if the file you're receiving contains binary data, then it's not a good idea to use fprintf with "%s" to write to the target file. This will stop writing as soon as it finds a '\0' byte (which is not uncommon in binary data). Use fwrite instead.
Even if you're receiving text (suggested by the html file extension), it's still not a good idea to use fprintf with "%s", since the received data won't be '\0' terminated.
This worked!
ps: I don't know if I should be doing this, since I am new here, but really there is no reason for negativity. Any question is a good question. Just answer it if you know it. Do not judge it.
#define MAXSIZE 1000
int bytes_read, thread_fd, new_file;
char buffer[MAXSIZE];
memset(buffer, 0, MAXSIZE);
if((new_file = open(path, O_RDONLY | O_WRONLY | O_CREAT)) < 0)
{
printf("can not open file \n");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0)
write(new_file, buffer, bytes_read);
close(new_file);

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.

Reading and Writing Files in C using read(...) write(...)

These commands are supposed to return bytes read or written.
Currently, I am trying to read and write 100 characters at a time.
When I use read(fd, buffer, 100) I get 99 characters read. When I use read(fd, buffer, 101) I get 100 characters read. What is the problem?
I am supposed to read 100 characters from a source code and write them to a destination1. Then, I am supposed to read 50 characters from same source into destination2.
The reading and passing is inaccurate after the first few loops. Problems arise on the third loop.
Please check it out:
[Step 2] Prcs_P2.c: Copy the contents of source.txt into destination1.txt and
destination2.txt as per the following procedure.
1. Read the next 100 characters from source.txt, and among characters read,
replace each character ’1’ with character ’A’ and all characters are then
written in destination1.txt
2. Then the next 50 characters are read from source.txt, and among characters
read, replace each character ’2’ with character ’B’ and all characters are
then written in destination2.txt
3. The previous steps are repeated until the end of file source.txt.
The last read may not have 100 or 50 characters.
-------------
It's copying characters irregularly. sometimes more than 100 | 50 and sometimes less.
int main() {
//const int sizeBuff=100;
char buffer[105]; //used to carry information in packets of 10
int temp=0; //temp variable to check for errors
int charCount=0;
int i=0;
//----------------------------------------
//charCount=read(sourceFile, buffer , 101 );
while( charCount=read(sourceFile, buffer , 100) >0){ //needed 101 as last arg instead of 100. DUnno why?
i=0;
while(i<charCount){
if (buffer[i]=='1')
buffer[i]='A';
i++;
}
if(write( destinationFile, buffer,charCount)==-1) //write(...) returns the number of bytes written to destinationFile
//-1 depicts error in the function and 0 is returned upon end of file
{
printf("\nWrite fail.\n");
perror("Error"); //Prints error, if found while writing.
}
memset(buffer, 0, 105); //CLEARS BUFFER
i=0;
charCount=read(sourceFile, buffer , 50 ); //reads 50 bytes at a time //need flag for error
while(i<charCount){
if (buffer[i]=='2')
buffer[i]='B';
i++;
}
temp=write( destinationFile2, buffer, charCount); //write(...) returns the number of bytes written to destinationFile
if(temp==-1) //-1 depicts error in the function and 0 is returned upon end of file
{
printf("\nWrite fail.\n");
perror("Error"); //Prints error, if found while writing.
}
memset(buffer, 0, 105);
}//while loop ends
close(destinationFile);
close(destinationFile2);
close(sourceFile);
//------PART 1 ENDS-------------
//------PART 2 STARTS------------
}
charCount=read(sourceFile, buffer , 100) >0
This sets charCount to 0 or 1. You want
(charCount = read(sourceFile, buffer , 100)) > 0

Resources