I was trying out some exercises with the C language, specifically open() and read(). However, I've reached an impasse when I try printing to STDOUT the contents of a a text file (text.txt) that I have in the same directory as the c file. The size in bytes get printed, but the contents of the file do not.
I allocated space according to the size of the file, and added "1" for the null terminator. The manual page for read() states that it reads the contents of the file into the second parameter (void* buff). What am I missing/doing wrong?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char* argv[]){
int fd = open("text.txt", O_RDONLY);
if (fd == -1){
printf("%s\n", strerror(errno));
return -1;
}
else {
int func = lseek(fd, 0, SEEK_END);
printf("%d bytes in size\n", func);
char* ptr = (char*)malloc(sizeof(char)*func + 1);
read(fd, ptr, func);
printf("%s", ptr);
free(ptr);
}
close(fd);
return 0;
}```
You need to move back to the beginning of the file before the read.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char* argv[]){
int fd = open("text.txt", O_RDONLY);
if (fd == -1){
printf("%s\n", strerror(errno));
return -1;
}
else {
int size = lseek(fd, 0, SEEK_END);
printf("%d bytes in size\n", size);
char* ptr = (char *) malloc(sizeof(char) * size + 1);
lseek(fd, 0, SEEK_SET); // move back to the beginning
read(fd, ptr, size);
printf("%.*s", size, ptr);
free(ptr);
}
close(fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char* argv[]){
int fd = open("text.txt", O_RDONLY);
if (fd == -1){
printf("%s\n", strerror(errno));
return -1;
}
else {
int size = lseek(fd, 0, SEEK_END);
printf("%d bytes in size\n", size);
char* ptr = (char *) malloc(sizeof(char) * size + 1);
lseek(fd, 0, SEEK_SET); // move back to the beginning
read(fd, ptr, size);
printf("%.*s", size, ptr);
free(ptr);
}
close(fd);
return 0;
}
(venv) [ttucker#zim stackoverflow]$ cat text.txt
asdf
qwer
sdfg
(venv) [ttucker#zim stackoverflow]$ gcc -o print print.c
(venv) [ttucker#zim stackoverflow]$ ./print
15 bytes in size
asdf
qwer
sdfg
Related
I am trying to make a C program that concatenates the contents of two files at a target file. To do this I must have at least 2 files open at the same time but I haven't figured out why I can't. The problem can be sufficiently described by the two pieces of code below:
Why does this work:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
size_t fdes = open(argv[1], O_RDONLY);
void * buf;
int bytes;
while ((bytes = (int)read(fdes, buf, 3)) > 0) {
printf("%s", (char*)buf);
}
close(fdes);
return 0;
}
and this doesn't?
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
size_t fdes = open(argv[1], O_RDONLY);
size_t fdes2 = open(argv[2], O_RDONLY);
void * buf;
int bytes;
while ((bytes = (int)read(fdes, buf, 3)) > 0) {
printf("%s", (char*)buf);
}
close(fdes);
close(fdes2);
return 0;
}
can't i have multiple files open?
I make some changes, and this works:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
size_t fdes = open(argv[1], O_RDONLY);
size_t fdes2 = open(argv[2], O_RDONLY);
size_t length = 0;
char * buf = (char *)malloc(sizeof(char) * length);
int bytes;
while ((bytes = (int)read(fdes, buf, sizeof(buf) - 1)) > 0) {
printf("%s", buf);
}
while ((bytes = (int)read(fdes2, buf, sizeof(buf) - 1)) > 0) {
printf("%s", buf);
}
close(fdes);
close(fdes2);
return 0;
}
First, buf should be char *
Second, you need to point buf to somewhere (malloc or a char array)
Reference: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.bpxbd00/rtrea.htm
I have 2 programs (write.c and read.c). I want to continuously write to the named pipe from standard input, and read from it on the other end (and write to standard output). I've made something work, but it isn't working right. The program on the other end reads in the wrong order or reads special characters (so it reads more then it needs?). I also want to be able to compare the named pipe output to a certain string.
Anyways, here's the code from both files:
write.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void main()
{
int fd, n;
char buf[BUFFSIZE];
mkfifo("fifo_x", 0666);
if ( (fd = open("fifo_x", O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, BUFFSIZE) ) > 0) {
if ( write(fd, buf, strlen(buf)) != strlen(buf)) {
err("write");
}
}
close(fd);
}
read.c:
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void main()
{
int fd, n;
char buf[BUFFSIZE];
if ( (fd = open("fifo_x", O_RDONLY)) < 0)
err("open")
while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
Example of input:
hello how are you
123
test
Example of incorrect output:
hello how are you
b123
o how are you
btest
how are you
b
Another example of input:
test
hi
And output:
test
hi
t
The buffer modify by read is not a valid c string so
write(fd, buf, strlen(buf)) != strlen(buf) // write.c
is undefined behaviour. You should do
write(fd, buf, n) != n
because you read n octet with read().
It's funny because you do it for read.c but not for write.c
The type of n must but ssize_t and not int, man read.
main() must return a int Declare main prototype
int fd, read_byte;
char *c;
fd = open("foo.txt", O_RDONLY);
read_byte = read(fd, c, 20);
printf("");
How to read last 20 bytes from a file and print the read_byte to the screen.
Use lseek(2)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd, read_byte;
char c[21];
fd = open("foo.txt", O_RDONLY);
if (fd == -1) {
printf("Error opening file\n");
return -1;
}
// reposition fd to position `-20` from the end of file.
lseek(fd, -20L, SEEK_END);
read_byte = read(fd, c, 20); // Read 20 bytes
c[read_byte] = '\0';
printf("%s\n", c);
close(fd);
return 0;
}
The following code fails when the buffer is on the stack, but succeeds when it's allocated on the heap. I tested it on RHEL 5.3 with a Raid drive. Is it possible to use O_DIRECT with stack buffers?
#define _GNU_SOURCE
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <malloc.h>
#define K 1024
#define ALIGNMENT (4*K)
#define RDSIZE (16*K)
#define BLOCKSIZE (512*K)
int main()
{
int flags = O_RDONLY | O_LARGEFILE;
int n = 0;
int fd = 0;
char* buf = (char *) memalign(ALIGNMENT, BLOCKSIZE);
//char buf[BLOCKSIZE] __attribute__((__aligned__(ALIGNMENT)));
assert(((long)buf) % ALIGNMENT == 0);
fd = open("test", flags | O_DIRECT);
if (fd < 0) {
perror("file open");
return -1;
}
n = read(fd, buf, RDSIZE);
if (n < 0) {
perror("file read");
return -1;
}
printf("%d\n", n);
close(fd);
}
UPDATE: Same code when compiled with Intel CC succeeds.
Check your stack size 512K is quite a lot.
If the problem is gcc misaligning buf, try this portable version instead:
char x_buf[BLOCKSIZE+PAGE_SIZE];
char *buf = buf + (PAGE_SIZE-1 & -(uintptr_t)x_buf);
I am having problem debugging why n_bytes in read_from_fifo function in client.c doesn't correspond to the value written to the fifo. It should only write 25 bytes but it tries to read a lot more (1836020505 bytes (!) to be exact). Any idea why this is happening?
server.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
typedef enum { false, true } bool;
//first read the int with the number of bytes the data will have
//then read that number of bytes
bool read_from_fifo(int fd, char* var)
{
int n_bytes;
if (read(fd, &n_bytes, sizeof(int)))
{
printf("going to read %d bytes\n", n_bytes);
if (read(fd, var, n_bytes))
printf("read var\n");
else {
printf("error in read var. errno: %d\n", errno);
exit(-1);
}
}
return true;
}
int main()
{
mkfifo("/tmp/foo", 0660);
int fd = open("/tmp/foo", O_RDONLY);
char var[100];
read_from_fifo(fd, var);
printf("var: %s\n", var);
return 0;
}
client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
typedef enum { false, true } bool;
//first write to fd a int with the number of bytes that will be written afterwards
bool write_to_fifo(int fd, char* data)
{
int n_bytes = (strlen(data)) * sizeof(char);
printf("going to write %d bytes\n", n_bytes);
if (write(fd, &n_bytes, sizeof(int) != -1))
if (write(fd, data, n_bytes) != -1)
return true;
return false;
}
int main()
{
int fd = open("/tmp/foo", O_WRONLY);
char data[] = "some random string abcdef";
write_to_fifo(fd, data);
return 0;
}
Help is greatly appreciated. Thanks in advance.
The return value for an error from read(2) is -1, not 0. So your if statement for the first 4-byte read, at least, is wrong.
Did you verify if nbytes printed by read_from_fifo() function displayed the correct value ?
Just notice that on write(fd, data, n_bytes) you did not write the end of string char '\0', and whenever you read it by read(fd, var, n_bytes), you did not added a '\0' to the end of string just read, so the printf("var: %s\n", var); could display a not \0 ended string resulting unpredicted results.
I have found the solution myself.
The problem is a ')' believe it or not. The n_bytes variable is correct, the problem is that I am not writing that to the fifo.
this (write(fd, &n_bytes, sizeof(int) != -1))
should be this (write(fd, &n_bytes, sizeof(int)) != -1)
Thanks anyway for your answers.