Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have to write a program in C in which I have to read some values from stdin and also to do it with the quickest function in C. The stdin is preloaded in a form like this:
int,int\n
char\n
int,int,int\n ex...
I'm asking for help because scanf is too slow for the time requirement of the project and also because I have some difficulties to read because of the ',' that I don't really need and that causes me problems.
I've tried with gets or getchar, but I didn't manage to make it work.
The fastest way to read stdin ("standard in" - 0 file descriptor) is to use read function from <unistd.h.>:
char buff[1024] = {0}; /* zero-initialize */
ssize_t res = read(0, &buff, sizeof(buff));
/* res is amount of bytes read; -1 if error */
Here is an example of program which reads 1024 bytes of stdin and echoes it to stdout (file descriptor: 1) (no error handling for simplicity):
#include <unistd.h>
#define BUFSIZ 1024
int main() {
char buff[BUFSIZ] = {0}; /* zero-initialize */
ssize_t nread = read(0, buff, BUFSIZ);
/* pass amount of bytes read as a byte amount to write */
write(1, buff, nread);
return 0;
}
This is the fastest way to read from stdin because read is native libc wrapper for a kernel syscall. By the way, you can use -O3, or even -Ofast compiler options to make it optimize the code.
Also, keep in mind that read and write are not guaranteed to read/write exactly as many bytes as you want, you should call it in a loop like this:
size_t to_write = sizeof(buff); /* example, can be result of read() */
int fd = 1;
size_t nwrote = 0;
while ((nwrote += write(1, buff, to_write) < to_write) {
/* pointer arithmetic to create offset from buff start */
write(fd, buff+nwrote, to_write - nwrote);
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I would like to merge two files using open and file descriptor. Moreover I would like to separate the content of the first file with - before writing the the content of the second file.
I did the following :
void merge (char* fileName, char *fileName1) {
int fd = open(fileName, O_RDWR);
char c;
while (read(fd, c, 1) > 0) {//going at the end of the first file
}
char next[] = "\n";
char charc[] = "-";
write (fd, next, strlen(next));
for (int i = 0; i < 80; i++) {
if (write (fd, charc, strlen(charc)) == -1) {
perror("error : ");
}
}
write (fd, next, strlen(next));
int fd1 = open(fileName1, O_RDWR);
while(read(fd1, &c, 1) > 0) {
write(fd, &c, sizeof(c));
}
close(fd1);
close(fd);
}
Is there a better way to write this code ? Moreover I have a little problem even if it works it seems like I don't have the right to read the new file. For example if I do cat newFile I have a permission denied.
Is there a better way to write this code ?
You are not handling errors of all calls. All of syscalls open, write, read and close return -1 on error and set errno and may do that at any time. EINTR could be handled.
going at the end of the first file open has O_APPEND flag mode that is used for appending data.
Copying one character at a time is very not optimal. With glibc standard library you could use BUFSIZ bytes at a time that is chosen for fast I/O output. You could make a copy of a big chunk size at a time that is a power of 2, like 2048 or 4096.
There is little reason to use file descriptors here - prefer to use standard FILE * handling, which would make your code portable and also buffer the data for faster I/O.
If you wish to create the file use O_CREAT and add the third argument to open that is the mask of permissions of new file.
On linux there is splice(2) system call that can be used to append data on kernel side for maximum efficiency.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm working on a data file that contains a fixed number of characters followed by a colon and then a number. All of the first four characters can be anything from all nulls to all (char)255s.
However, when trying to read it, I'm having trouble determining the EOF.
If I use posix's read(2) like so:
ssize_t letters_read = read(fd, buf, 4);
Then letters_read is set to 0. The man page says that means I've reached an EOF; however, this is simply not true.
If I use fread(3) in a similar way, then I still get zero as a return value. Even when sending the file to feof(3), it says I'm at the end of file.
Now, if I just ignore the return values, then I'm able to continue reading the file and get further results.
How would I be able to read all four nulls and still be able to know when I've reached an eof?
A small excerpt of the file looks like this:
4
(null)(null)(null)(null):4
(null)(null)(null)(null):40
(null)(null)(null)(null):402
Af*8:3004
UPDATE
As per request, here is how I'm going about collecting data:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
void process_characters(char *data);
int main(int argc, char *argv[])
{
char *input_file = argv[1];
int opt = 0;
int input_fd = open(input_file, O_RDONLY);
FILE *temp_fd = fopen(input_file, "r");
unsigned long character_size = 0;
fscanf(temp_fd, "%l", character_size);
char data[character_size];
//gobble up the first line
do
{
read(input_fd, data, 1);
printf("%i\n", data[0]);
} while(data[0] != '\n');
size_t characters_read = 0;
characters_read = read(input_fd, data, character_size);
//while(feof(temp_fd) != 0)
while(characters_read != 0)
{
//fread(data, sizeof(char), character_size, temp_fd);
process_characters(data);
///gobble up the garbage
do
{
read(input_fd, data, 1);
printf("%i\n", data[0]);
}while(data[0] != 10);
characters_read = read(input_fd, data, character_size);
}
fclose(temp_fd);
close(input_fd);
return EXIT_SUCCESS;
}
This code:
unsigned long character_size = 0;
fscanf(temp_fd, "%l", character_size);
... has an invalid format specified, and needs to provide the variable address rather than its value. "%l" does not specify a type to read. Perhaps you want "%lu" which is for an unsigned long integer, which is how character_size is defined. character_size should be &character_size.
However, there is no such (decimal) value at the beginning of the sample file you have provided, so it is unclear what this fscanf line is really supposed to do.
(You claimed that using read as follow returns 0:
ssize_t letters_read = read(fd, buf, 4);
However, there is no such line in your code).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
can someone explain me how does int setvbuf(FILE *stream, char *buffer, int mode, size_t size) C function works?
I think it sets a buffer for a file stream and stores data in the buffer allocated by setvbuf in size_t size chunks of data, am I right? And when the buffer is full it is flushed?
sorry I am new here
I assume you did search google, but you need some help understanding what you have found:
I am quoting interchangeably gnu documentation and cppreference:
int setvbuf (FILE *stream, char *buf, int mode, size_t size)
After opening a stream (but before any other operations have been
performed on it), you can explicitly specify what kind of buffering
you want it to have using the setvbuf function. The facilities listed
in this section are declared in the header file stdio.h.
The arguments description:
stream - the file stream to set the buffer to
buffer - pointer to a buffer for the stream to use
mode - buffering mode to use. It can
be one of the following values:
_IOFBF full buffering
_IOLBF line buffering
_IONBF no buffering
size - size of the buffer
If you switch for the c documentation in cppreference you will find the following example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int file_size;
char buffer[BUFSIZ];
FILE * fp = fopen("test.txt","w+");
if (setvbuf(fp,buffer,_IOFBF,BUFSIZ) != 0)
{
perror("setvbuf()");
fprintf(stderr,"setvbuf() failed in file %s at line # %d\n", __FILE__,__LINE__-3);
exit(EXIT_FAILURE);
}
/* Exhibit the contents of buffer. */
fputs ("aaa",fp);
printf("%s\n", buffer);
fputs ("bbb",fp);
printf("%s\n", buffer);
fputs ("ccc",fp);
printf("%s\n", buffer);
file_size = ftell(fp);
printf("file_size = %d\n", file_size);
fflush (fp); /* flush buffer */
printf("%s\n", buffer);
fputs ("ddd",fp);
printf("%s\n", buffer);
fputs ("eee",fp);
printf("%s\n", buffer);
rewind(fp); /* flush buffer and rewind file */
char buf[20];
fgets(buf,sizeof buf,fp);
printf("%s\n", buf);
fclose(fp);
return 0;
}
Output:
aaa
aaabbb
aaabbbccc
file_size = 9
aaabbbccc
dddbbbccc
dddeeeccc
aaabbbcccdddeee
Pay attention for the following things:
What happens when you fflush the FILE *fp.
What buffer contains after fputs string to fp.
What happens when you rewind(fp), reread from the file all you have been written.
Don't be afraid of documentation/ manual pages, if you get used to them and read them you will be a great developer, moreover now you are familiar with http://en.cppreference.com/, which is very good source to get start with new API functions, good luck.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am trying to copy data from a file containing HEX characters to my embedded device's SRAM memory over UART from Matlab. The problem is I don't know how to make the program stop treating any of the received characters as a special command.
For eg: the symbol '' has HEX equivalent of 0x20 as per the ASCII table. However,it may happen that my data has this 0x20 somewhere. So, i can't use this as a delimiter for my program.
Please suggest me a way by which all the data from the hex file can be read without causing any such issues.
This is the part of my code.
memcpy(((uint8_t*)(SRAM_BASE+i)),&cThisChar,1);
UARTCharPut(UART0_BASE, cThisChar);
i++;
//
// Stay in the loop until either a CR or LF is received.
//
}
while((cThisChar != '\n') && (cThisChar != '\r')); // this is where the problem happens!
So what should I put a condition for the while loop so that it accepts all characters?
Thanks!
Do not try to get the end of file by its content.
Get its size and use a counter instead.
FILE *fp = NULL;
long int fsize = 0;
long int fptr = 0;
/* Open file. */
/* todo: Open file here. */
/* Get file size. */
fseek(fp, 0L, SEEK_END);
fsize = ftell(fp);
fseek(fp, 0L, SEEK_SET);
/* Process file data. */
while (fptr < fsize) {
/* todo: Do your stuff here. */
++fptr;
}
/* Close file. */
/* todo: Close file here. */
Basically,this is all what I wanted to achieve! Thanks for your effort anyways!
signed char cThisChar;
while (cThisChar != EOF);
I am posting the solution.
while (j < 2048)
{
do
{
//
// Read a character using the blocking read function. This function
// will not return until a character is available.
//
cThisChar = UARTCharGet(UART0_BASE);
//
// Write the same character using the blocking write function. This
// function will not return until there was space in the FIFO and
// the character is written.
//
memcpy(((uint8_t*)(SRAM_BASE+i)),&cThisChar,1);
UARTCharPut(UART0_BASE, cThisChar);
i++;
//
// Stay in the loop until either a CR or LF is received.
//
} //while((cThisChar != '\n') && (cThisChar != '\r'));
while (i<17);
j++;
}
This is part of the code from the microcontroller side. After repeated iterations, I found out that using a buffer value of 16 was the best option. j is the outer loop counter = 32768/16 = 2048. by this I can write all the 32768 bytes in packets of 16 bytes.
And now the corresponding MATLAB version of the code:
while(true)
txdata = fread(A,**16**,'uint8','ieee-be');
%[my_count_rows, my_count_columns]=size(txdata);
%Convert to decimal format
%txdata_dec = hex2dec(txdata);
%Write using the UINT8 data format
**fwrite(obj1,txdata(1:16),'uint8');**
if txdata > 32768
break;
end
end
I'm having a hard time trying to figure out why this piece of code doesn't work as it should. I am learning the basics of I/O operations and I have to come up with a C program that writes on a 'log.txt' file what is given from standard input and as the 'stop' word is entered, the program must halt.
So my code is:
#include "main.h"
#define SIZE 1024
int main(int argc, char *argv[])
{
int fd;
int readBytes;
int writBytes;
char *buffer;
if ((fd = open("log.txt", O_WRONLY|O_APPEND)) < 0)
{
perror("open");
}
buffer = (char *) calloc (SIZE, sizeof(char));
while ((readBytes = read(0, buffer, SIZE) < SIZE)&&(strncmp(buffer, "stop", 4) != 0));
if ((writBytes = write(fd, buffer, SIZE)) < 0)
{
perror("write");
}
if ((close(fd)) < 0)
{
perror("close");
}
}
If I enter:
this is just a text
stop
The output is
stop
is just a text
If I enter more than a sentence:
this is just a text
this is more text
and text again
stop
This is what is logged:
stop
ext again
xt
t
And on top of that if I try to edit the log.txt file from vim or just a text editor I can see '\00's. I guess \00 stands for all the bytes left empty from the 1024 available, right? How can I prevent that from happening?
It looks like you're expecting
readBytes = read(0, buffer, SIZE) < SIZE)
to somehow accumulate things in buffer. It doesn't. Every subsequent read will put whatever it read at the start of the buffer, overwriting what the previous read has read.
You need to put your write in the while block - one write for every read, and only write as much as you read, otherwise you'll write garbage (zeros from the calloc and/or leftovers from the previous read) in your log file.
Also note that while your technique will probably work most of the time for a line-buffered input stream, it will not do what you expect if you redirect from a file or a pipe. You should be using formatted input functions (like getline if you your implementation has that, scanf, or fgets).