Number of bytes read from a pipe - c

When reading from a pipe in Linux (C, fread/similar), when EOF is reached, how can it be known how many bytes were read? If I read blocks at a time, fread() only returns the number of full blocks read in, and I can't read one byte at a time because that is too slow. Of course, ftell() returns -1.

You can do this with fread() by setting the size param to 1 and set the nmembers to whatever size you like. Then the number of "members" is the number of bytes and you can still have a decent sized buffer:
char buf[8192];
size_t n;
n = fread(buf, 1, sizeof buf, f);
instead of
char buf[8192];
size_t n;
n = fread(buf, sizeof buf, 1, f);

read() returns the number of bytes read (when nothing goes wrong).

Related

Fill char array from an advanced array position

I'm coding two programs that communicates via sockets sendinc char * strings.
Sometimes, read() reads less bytes than it should, so I gotta loop that read() till all the bytes are read. But, for example, if I want to read a string of 100 bytes, and read() only receives 60 (40 are missing in the socket buffer), means the string has only data in it's 60 first positions. Now I'd want to loop the read() to read those extra 40 bytes but, how can I tell the read() function to store those bytes from the position 60 of the previously filled string in order not to overwrite the information before read?
char string[100];
ssize_t total_bytes = 100;
ssize_t bytes_read = 0;
do {
//How can I read and store the array of chars in the variable string being string[bytes_read] the starting point in each iteration?
bytes_read = read(socket, string/*?*/, total_bytes);
total_bytes -= bytes_read;
} while(total_bytes > 0);
You can add an integer to the pointer (converted from the array, pointing at the first element of the array) to advance the position to start writing what is read.
bytes_read = read(socket, string + (100 - total_bytes), total_bytes);
If you definitely want the start point to be string[bytes_read] (it will make it overwrite some data if 3 or more reads are done):
bytes_read = read(socket, string + bytes_read, total_bytes);
or this may be easier (straight-forward):
bytes_read = read(socket, &string[bytes_read], total_bytes);

Need a function like read() that reads integer data into buffer and obtains same buffer value as read()

How can I convert integer into value/encoded character same as the buffer obtained with read(0,buff,nbytes) when I stdin same integer? Am attempting to write something similar like read() but with integer data in place of file descriptor argument that gets read into buffer.
like_read(int data,void *buff,size_t nbytes);
It should be similar to read() in the sense that it should read into buffer same value that read(0,buff,nbytes) would from stdin into its buffer. when I provide integer address directly as buffer without first using read(0,buff,nbytes), for example
int Integer=25
int nbytes=2;
int rlen,wlen,wlen1;
int fd = open("ttyusb.txt", O_RDWR | O_CREAT,0777);
wlen = write(fd, &Integer, nbytes);
wlen1 = write(1, &Integer, nbytes);//for stdout
close(fd);
Expected output
25
Actual output/file content is some encoded character
,its not giving me the desired result as first using read() to read integer into buffer from stdin and then writing that buffer into file using write() like:
int Integer;
int nbytes=2;
int rlen,wlen;
int fd = open("ttyusb.txt", O_RDWR | O_CREAT,0777);
rlen = read(0, &Integer, nbytes);
wlen = write(fd, &Integer, nbytes);
wlen1 = write(1, &Integer, nbytes);//for stdout
close(fd);
Stdin
25
Expected output
25
Actual output/file content
25
when I print buffer value after read(0, buffer, nbytes), it gives some encoded value:
int Integer, nbytes=2;
int fd = open("ttyusb.txt", O_RDWR | O_CREAT,0777);
rlen = read(0, &Integer, nbytes);
wlen = write(fd, &Integer, nbytes);
wlen1 = write(1, &Integer, nbytes);
printf("\nInteger buffer value %d\n",Integer);
close(fd);
stdin 0 prints "Integer buffer value 2608", stdin 1 prints "Integer buffer value 2609", stdin 2 prints "Integer buffer value 2610",.....stdin 9 prints "Integer buffer value 2617"...
what encoding is read() using to convert integer values and how can I do that conversion without read()?
I'm not really sure what you are trying to achieve, but my interpretation is that you are trying to copy the bytes of an int into a buffer. That could be implemented something like this:
#include <string.h>
void like_read(int data, void *buff, size_t nbytes)
{
size_t n;
/* Limit number of bytes to copy from data variable. */
n = sizeof(data);
if (n < nbytes)
n = nbytes;
/* Copy bytes from data variable to the buffer. */
memcpy(buff, &data, n);
/* If destination buffer is larger than data variable, ... */
if (n < nbytes) {
/* ... set the remaining bytes in the destination to all zero. */
memset((char *)buff + n, 0, nbytes - n);
}
}
what encoding is read() using to convert integer values and how can I do that conversion without read()?
read() just reads raw data bytes from the file descriptor, without any conversion, at least on POSIX type systems such as Unix and Linux. Some other operating systems such as Microsoft Windows allow files to be opened with special flags that do some conversion on the raw data bytes, mostly for handling text files with different encodings.
The memcpy() call in the like_read function above copies raw data bytes from one memory location to another without any conversion.
EDIT
I am still not sure what you (OP) are trying to achieve, but based on your comments below, perhaps you are after a function that "prints" the integer value as decimal ASCII characters to the buffer with a newline, but truncates to a specified number of bytes. This can nearly be done by snprintf() but that function always writes a terminating null byte to the buffer (if the buffer size is at least 1), so isn't quite what I think you want. Therefore, snprintf() can be used to print the integer value to an intermediate buffer of sufficient size and then memcpy the result to the specified buffer. Here is an implementation of that:
#include <string.h>
#include <stdio.h>
void like_read(int data, void *buff, size_t nbytes)
{
char tempbuf[24]; /* ought to be large enough... */
size_t n;
/* Print data value to temporary buffer. */
n = snprintf(tempbuf, sizeof(tempbuf), "%d\n", data);
/* n is number of bytes that would be printed to tempbuf if room. */
/* Limit number of bytes to copy to size of temporary buffer. */
if (n > sizeof(tempbuf))
n = sizeof(tempbuf);
/* Limit number of bytes to copy to nbytes. */
if (n > nbytes)
n = nbytes;
/* Copy bytes from tempbuf to the buffer. */
memcpy(buff, tempbuf, n);
/* If destination buffer is larger than n, ... */
if (n < nbytes) {
/* ... set the remaining bytes in the destination to all zero. */
memset((char *)buff + n, 0, nbytes - n);
}
}

How to read a large file with function read() in C

Aloha,
I'm new here, so please take it easy on me.
I'm trying to read a file with function read() and then write() to a file or a file descriptor. My function successfully reads a file, but a problem occurs when I try to read a larger file(in my example size of 40,000 bytes).
I think that I must write a while loop, which will be reading until the end of a file, but I am stuck on the idea of how to..
(I open a file or file descriptor in main of the program)
My function( also convert binary input char data and writes to the ASCII) :
void function(int readFrom,int writeOn){
char buffer[100];
int x = read(readFrom, buffer, sizeof(buffer));
int size= x/8;
int i;
for(i=0; i<size; i++){
char temp[sizeof(int)-1];
sprintf(temp,"%d",buffer[i];
write(writeOn, temp, sizeof(temp));
}
}
You need to check return value of functions read and write. They return the number of bytes read/written that may be less than the number that you passed as third argument. Both read and write must be done in a loop like:
int bytesRead = 0;
while (bytesRead < sizeof(buffer)) {
int ret = read(readFrom, buffer + bytesRead, sizeof(buffer) - bytesRead);
if (ret == 0)
break; / * EOF */
if (ret == -1) {
/* Handle error */
}
bytesRead += ret;
}
You use sprintf() to convert characters from buffer into a very small buffer temp. On most current systems, int is 4 bytes, so your printf causes buffer overflows for char values greater than 99 (ASCII letter 'c'). Note that char can be signed by default, so negative values less than -99 will require 5 bytes for the string conversion: 3 digits, a minus sign and a null terminator.
You should make this buffer larger.
Furthermore, I don't understand why you only handle x/8 bytes from the buffer read by the read() function. The purpose of your function is obscure.

Reading fully from file descriptor of unknown size

I have used pipe and I have to read from this pipe. But problem is this:
ssize_t read(int fd, void *buf, size_t count)
I don't know how many characters is stored in the reading end of pipe, so I can't assign some number to count. I need this to store in the buffer.
How can I number of characters stored in this pipe?
With regards
I don't know how many characters is stored in the reading end of pipe
Don't worry about it. There are advantages (e.g. atomicity) to not trying to write/read more than PIPE_BUF bytes at shot. In reality you will probably get a bunch of short reads anyway.
#define READ_BUFFER_SIZE PIPE_BUF
unsigned char mybuffer[READ_BUFFER_SIZE];
ssize_t bytesread = 1;
while ((bytesread = read(pipefd, mybuffer, READ_BUFFER_SIZE)) > 0)
{
concat to bigger buffer, realloc if necessary
}
Just use a reasonably sized buffer, and read as much as you can. Repeat that. The function returns the number of bytes read.
You need not know before hand how many bytes are there and pass that as as a value for count.
You can define buffer of maximum data size that you can expect and read from the fd until data is present.
char buf[MAX_DATA_SIZE] = {0};
bytes_read = 0;
while(n > 0)
{
n = read(fd,buf+bytes_read,MAX_DATA_SIZE)
bytes_read = bytes_read + n;
}
You can simply request the number of characters up to the size of your buffer, and do so repeatedly in a loop, e.g:
char* buf = malloc(1024);
do {
bytes_read = read(fd, buf, 1024);
// store buf somewhere else so you can use it in the next iteration
} while (bytes_read > 0)
free(buf);

While doing fread() into an integer, what happens if file size is not a multiple of 4 bytes?

I am implementing a Feistel cipher of block size 16 bits. I read from an input file into an integer (32bits), encrypt and write to output file.
unsigned int buf1, buf2;
FILE *fin = fopen("input", "r");
FILE *fout = fopen("output", "w");
while(!feof(fin)) {
fread(&buf1, 4, 1, fin);
buf2 = encrypt(buf1);
fwrite(&buf2, 4, 1, fout);
}
The program is almost done. The only problem is that encryption followed by decryption is not the source file. They're almost same but the difference is only in the last bits.
My question is what happens if the no of bytes in the file is not a multiple of 4. What will happen to the last call to fread()?
If the number of bytes in the file is not a multiple of 4, the last call to fread() will return 0.
size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
"The fread function returns the number of elements successfully read, which may be less than nmemb if a read error or end-of-file is encountered."
The result value of fread() should be used to detect an incomplete read and EOF. OP code, as is, will read once too often.
Also suggest using uint32_t instead of unsigned int for greater portability and checking `fwrite() results.
uint32_t buf1, buf2;
int cnt;
while((cnt = fread(&buf1, sizeof buf1, 1, fin)) == 1) {
buf2 = encrypt(buf1);
if (fwrite(&buf2, sizeof buf2, 1, fout) != 1) {
Handle_WriteError();
}
}
You need to know the size of the file you are reading in advance (using stat() or equivalent), read the number of complete blocks available and then handle the residual bytes, if any, as a special case, perhaps by padding. If you don't want ciphertext expansion, then look at block stealing modes of operation, which are available for both ECB and CBC modes.

Resources