I'm trying to read a binary file on Windows 7 with a program compiled by MinGW. The binary file is ~10M in size but my program can only read less than 1000 bytes and it thinks it reached EOF.
Here is the code. I'm sure I'm doing something stupid but I just can't seem to find it.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define TS_FILE "foo.data"
int main(void)
{
int fd;
int r;
unsigned char buf[1024];
fd = open(TS_FILE, O_RDONLY|O_BINARY);
printf("fd: %d\n", fd);
if ( fd == -1 )
{
exit(0);
}
for (;;)
{
r = read(fd, buf, 1000);
if ( r != 1000 )
{
printf("read error. %d\n", r);
perror("read");
}
if ( r == 0 )
{
break;
}
}
close(fd);
}
The program will say it reads 736 bytes and that's the EOF.
Could somebody tell me what is going on? Thanks!
Thanks,
In fact, your program is indeed reading the entire file. It reads the file 1000 bytes at a time until there are, in this case, 736 bytes left. Then it reads those final 736 bytes and read returns 736. You are mistakenly treating the inability to read the full 1000 bytes as an error, but it is not an error. If read fails then the error condition is marked by the return value being -1.
Your loop should perhaps be more like this:
for (;;)
{
r = read(fd, buf, 1000);
if (r == -1)
{
printf("read error\n");
perror("read");
exit(1);
}
if (r != 1000)
{
//entire file has been read
break;
}
}
close(fd);
A couple of other points:
The correct type for r is size_t.
Rather than hardcoding 1024 and 1000, you would be better with something like #define BUFFLEN 1024 so that you don't keep repeating those magic values.
Related
My program is supposed to take text from a file given in the command line change it to uppercase and store it in another file.
It works except the output file has a whole bunch of garbage after the converted text. Thank you
Edit: I changed my read to check for 0 bytes and used ret_in to write per Pyjamas it still pulls two or three garbage values. It's definitely read getting the garbage because when I output the buffer before converting it's there.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUF_SIZE 500
int main(int argc, char* argv[]){
char buffer[BUF_SIZE];
int ret_in;
char inputf[100],outputf[100],txt[4],up[3];
// Takes input and adjusts it to the correct file type.
strcpy(inputf,argv[1]);
strcpy(outputf,argv[1]);
strcat(outputf,".up");
printf("%s\n",outputf);
strcat(inputf,".txt");
printf("%s\n",inputf);
int output, input,wrt;
int total;
//opens input file
input=open(inputf, O_RDONLY);
if (input == -1) {
printf("Failed to open file\n");
exit(1);
}
ret_in = read(input,buffer,BUF_SIZE);
total = ret_in;
// output to console
while (ret_in!= 0) {
// printf("%s\n", buffer);
ret_in = read(input,buffer,BUF_SIZE);
total += ret_in;
}
//ret_in= read(input,&buffer,BUF_SIZE);
puts(buffer);
close(input);
int i = 0;
while(buffer[i]) {
buffer[i] = toupper(buffer[i]);
i++;
}
// output buffer in console
puts(buffer);
//output filename in console
printf("%s\n",outputf);
// Opens or creates output file with permissions.
output = open(outputf, O_CREAT| S_IRUSR | O_RDWR);
if (output == -1) {
printf("Failed to open or create the file\n");
exit(1);
}
// write to output file
wrt = write(output, buffer,total);
close(output);
return 0;
}
Because you read ret_in bytes from file, but you write BUF_SIZE to the file, you should write ret_in bytes to the file. You are not supposed to read BUF_SIZE bytes from file every time, it depends, right?
write(output, buffer,BUF_SIZE);//wrong
write(output, buffer,ret_in); //right
I am currently writing a small dummy program to try and get the hang of properly using the read in c. I made a small function called readdata to read from the file descriptor and store in a buffer then return the number of bytes read. My problem is I am trying to correctly error handle and trap things so that there is no buffer overflow but I keep doing something from.
Here is the tester:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 10
int readdata(int fd, char *buf, int bsize);
int main(void) {
char buf[BUFSIZE];
int returnval;
int length;
returnval = readdata(STDIN_FILENO, buf, BUFSIZE);
printf("%s",buf);
length = strlen(buf);
fprintf(stderr,"The return value is %d\n", returnval);
fprintf(stderr,"The string is %s\n",buf);
fprintf(stderr,"The length of the string is %d\n",length);
return 0;
}
Here is the small function:
#include <stdio.h>
#include <stdlib.h>
int readdata(int fd, char *buf, int bufsize){
int n = 0;
if(fd < 0){
return 1;
}
while((n=read(fd,buf,(bufsize-1)))>0){
if(n == -1) {
perror( "Read failed" );
return 1;
}
else{
buf[bufsize] = 0;
return n;
}
}
}
If I run
cc -o test test.c readdata.c
And then put
echo "Hello" | ./test
It works fine. But if I pass the bufsize limit like this:
echo "1234567891" | ./getdatatest
It gives me this weird output where it says "the string is 123456789[some weird symbol]" . So I am not sure where to handle this error or why it is still incorrectly putting in the buffer when reading.
You do know that read() can return less characters than you requested? Also, buf[bufsize] is just past the end of buf. Your readdata function should also return something like -1 on error instead of 1 so you can distinguish the condition “one byte read” from “IO error.”
Consider something like this:
for (;;) {
n = read(fd, buf, (bufsize - 1));
if(n == -1) {
perror( "Read failed" );
return -1;
} else {
buf[n] = 0;
return n;
}
}
I am trying to write a program on how to read a file 10 bytes per time using read, however, I do not know how to go about it. How should I modify this code to read 10bytes per time. Thanks!!!!
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
int main (int argc, char *argv[])
{
printf("I am here1\n");
int fd, readd = 0;
char* buf[1024];
printf("I am here2\n");
fd =open("text.txt", O_RDWR);
if (fd == -1)
{
perror("open failed");
exit(1);
}
else
{
printf("I am here3\n");
if(("text.txt",buf, 1024)<0)
printf("read error\n");
else
{
printf("I am here3\n");
/*******************************
* I suspect this should be the place I make the modification
*******************************/
if(read("text.txt",buf, 1024)<0)
printf("read error\n");
else
{
printf("I am here4\n");
printf("\nN: %c",buf);
if(write(fd,buf,readd) != readd)
printf("write error\n");
}
}
return 0;
}
The final parameter of read() is the maximum size of the data you wish to read so, to try and read ten bytes at a time, you would need:
read (fd, buf, 10)
You'll notice I've also changed the first parameter to the file descriptor rather than the file name string.
Now, you'll probably want that in a loop since you'll want to do something with the data, and you also need to check the return value since it can give you less than what you asked for.
A good example for doing this would be:
int copyTenAtATime (char *infile, char *outfile) {
// Buffer details (size and data).
int sz;
char buff[10];
// Try open input and output.
int ifd = open (infile, O_RDWR);
int ofd = open (outfile, O_WRONLY|O_CREAT);
// Do nothing unless both opened okay.
if ((ifd >= 0) && (ofd >= 0)) {
// Read chunk, stopping on error or end of file.
while ((sz = read (ifd, buff, sizeof (buff))) > 0) {
// Write chunk, flagging error if not all written.
if (write (ofd, buff, sz) != sz) {
sz = -1;
break;
}
}
}
// Finished or errored here, close files that were opened.
if (ifd >= 0) close (ifd);
if (ofd >= 0) close (ofd);
// Return zero if all okay, otherwise error indicator.
return (sz == 0) ? 0 : -1;
}
change the value in read,
read(fd,buf,10);
From man of read
ssize_t read(int fd, void *buf, size_t count);
read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
if(read("text.txt",buf, 1024)<0)// this will give you the error.
First argument must be an file descriptor.
I am learning "Advanced Programming in Unix Environment", and have a problem with exercise no.11 in chapter 10.
In my program, I set RLIMIT_FSIZE to 1024.
So the kernel should send SIGXFSZ to my program when write trying to exceed that limit.
But I found that SIGXFSZ is not send unless something is printed to stdout.
Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#define BUFFSIZE 100
void xfsz_handler(int signo)
{
fprintf(stderr, "%d, %s\n", signo, strsignal(signo));
}
int main(int argc, char* argv[])
{
int n;
char buf[BUFFSIZE];
struct rlimit fsizeLimit;
fsizeLimit.rlim_cur=1024;
fsizeLimit.rlim_max=1024;
if(setrlimit(RLIMIT_FSIZE, &fsizeLimit) < 0)
{
perror("setrlimit error");
exit(-1);
}
if(signal(SIGXFSZ, xfsz_handler)==SIG_ERR)
{
fprintf(stderr, "set signal handler error for %d\n", SIGXFSZ);
exit(-1);
}
printf("what ever\n"); /* we need this to get SIGXFSZ sent */
while ( (n=read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
{
int byteWrite = 0;
if ( (byteWrite = write(STDOUT_FILENO, buf, n)) < 0)
{
perror("write error");
exit(-1);
}
if(byteWrite!=n)
{
fprintf(stderr, "byteWrite=%d, n=%d\n", byteWrite, n);
exit(-1);
}
}
if (n<0)
{
perror("read error");
exit(-1);
}
return 0;
}
if I comment out the following line in the code, kernel will not transmit SIGXFSZ.
printf("What ever . . . \n");
Why this happens? Thanks in advance.
[root#luaDevelopment ex11]# ./myCopy < /root/workspace/AdvanceProgrammingInTheUnixEnvironment.20140627.tar.bz2 >aa.tar.bz2
byteWrite=24, n=100
[root#luaDevelopment ex11]# make
gcc -o myCopy myCopy.c -std=gnu99 -I../../lib/ -L../../lib/ -lch10
[root#luaDevelopment ex11]# ./myCopy < /root/workspace/AdvanceProgrammingInTheUnixEnvironment.20140627.tar.bz2 >aa.tar.bz2
byteWrite=24, n=100
25, File size limit exceeded
[root#luaDevelopment ex11]#
user3693690 found the answer in Appendix C of the book:
10.11 Under Linux 3.2.0, Mac OS X 10.6.8, and Solaris 10, the signal handler for SIGXFSZ is never called because the loop exits the program on a short write, but write returns a count of 24 as soon as the file’s size reaches 1,024 bytes. When the file’s size has reached 1,000 bytes under FreeBSD 8.0, the signal handler is called on the next attempt to write 100 bytes, and the write call returns −1 with errno set to EFBIG("File too big"). On all four platforms, if we attempt an additional write at the current file offset (the end of the file), we will receive SIGXFSZ and write will fail, returning −1 with errno set to EFBIG.
I have a piece of code written in POSIX compliant C and it doesn't seem to work correctly. The goal is to read from /dev/random, the interface to the Linux/BSD/Darwin kernel's random number generator and output the written byte to a file. I'm not quite sure what I'm overlooking as I'm sure I've covered every ground. Anyway, here it is:
int incinerate(int number, const char * names[]) {
if (number == 0) {
// this shouldn't happen, but if it does, print an error message
fprintf(stderr, "Incinerator: no input files\n");
return 1;
}
// declare some stuff we'll be using
long long lengthOfFile = 0, bytesRead = 0;
int myRandomInteger;
// open the random file block device
int zeroPoint = open("/dev/random", O_RDONLY);
// start looping through and nuking files
for (int i = 1; i < number; i++) {
int filePoint = open(names[i], O_WRONLY);
// get the file size
struct stat st;
stat(names[i], &st);
lengthOfFile = st.st_size;
printf("The size of the file is %llu bytes.\n", lengthOfFile);
while (lengthOfFile != bytesRead) {
read(zeroPoint, &myRandomInteger, sizeof myRandomInteger);
write(filePoint, (const void*) myRandomInteger, sizeof(myRandomInteger));
bytesRead++;
}
close(filePoint);
}
return 0;
}
Any ideas? This is being developed on OS X but I see no reason why it shouldn't also work on Linux or FreeBSD.
If it helps, I've included the following headers:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
Instead of
write(filePoint, (const void*) myRandomInteger, sizeof(myRandomInteger));
you surely meant to write
write(filePoint, (const void*) &myRandomInteger, sizeof(myRandomInteger));
didn't you? If you use the random bytes read from /dev/random as a pointer, you're almost certain to encounter a segfault sooner or later.