Hi I am trying to read from a file and print it on terminal. But fwrite() does not print anything. Can anyone please help! I cannot see the output from the file on the terminal. After debugging all I can see is program is not entering into while loop used before fwrite().
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#define BUF_SIZE 128
int main(int argc, char* argv[])
{
int BATT_fd, ret_write, ret_read, i;
char buffer[BUF_SIZE];
if(argc != 2)
{
printf ("\nUsage: cp file1 file2\n");
return 1;
}
BATT_fd = open (argv [1], O_RDWR | O_CREAT, S_IRWXU);
if (BATT_fd == -1)
{
perror ("open");
return 2;
}
printf("\n file opened successfully with file desc %d\n", BATT_fd);
printf("enter data into file\n");
scanf("%[^\n]", buffer);
if((ret_write = write (BATT_fd, &buffer, BUF_SIZE)) == 0)
{
printf("nothing is write");
}
else if((ret_write = write (BATT_fd, &buffer, BUF_SIZE)) == -1)
{
printf("write error");
}
else
{
printf("wrote %d characters to file\n", ret_write);
printf("address writeen is %x\n", buffer[i]);
}
if((ret_read = read(BATT_fd, &buffer, BUF_SIZE)) > 0)
{
perror("read");
return 4;
}
else
{
while((ret_read = read (BATT_fd, &buffer, BUF_SIZE)) > 0)
{
fwrite(buffer, 1, ret_read, stdout);
}
}
close (BATT_fd);
return 0;
}
output:
Before reading data from file, you need to move current position in file to the begining. That's because your write operations have moved current position to the end of file, so there is nothing left for reading ;).
see fseek
EDIT:
lseek would be better in your case (see comments)
Related
I want a program which reads a file in the child process and send the string/content to the parent process using simple pipe.
Here is what I have tried, I have read a file and tried to write into the pipe line by line in the while loop. But It doesn't seem to work that way. Your help will be highly appreciated.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE * fptr;
fptr = fopen(argv[1],"r");
char str1;
int pipefds[2];
char buffer[5];
if(pipe(pipefds) == -1)
{
perror("PIPE ERROR");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if(pid == 0)
{
char singleLine[150];
close(pipefds[0]);
while(!feof(fptr))
{
fgets(singleLine, 150, fptr);
//puts(singleLine);
write(pipefds[1], singleLine, sizeof(singleLine));
}
fclose(fptr);
//Close read file descriptor
exit(EXIT_SUCCESS);
}
else if(pid > 0)
{
//wait(NULL); //Wait for child process to finish
close(pipefds[1]); //Close write file descriptor
read(pipefds[0], buffer, 100); //Read pin from pipe
close(pipefds[0]); //Close read file descriptor
printf("%s",buffer);
}
return 0;
}
Check for Program Argument
To ensure that the filename parameter is provided, you could check as follows:
if (argc < 2) {
fprintf(stderr, "usage: progname <filename>");
exit(EXIT_FAILURE);
}
Opening the File
Presumably it makes sense to check whether fopen is successful or not.
You could do a check e.g. like this:
if ((fptr = fopen(argv[1], "r")) == NULL) {
perror("error opening file");
exit(EXIT_FAILURE);
}
Also like mentioned by #pat in the comments this code can be moved to the child.
Reading the file
Reading the file could be done like this:
while (fgets(singleLine, sizeof(singleLine), fptr)) {
write(pipefds[1], singleLine, strlen(singleLine));
}
Like mentioned by Jonathan Leffler in the comments one should not check feof upfront. Also important to note that you don't want to write sizeof(singleLine) bytes, because lines can have variable size and be shorter then the buffer size, so better to use strlen(singleLine) here.
Reading the Data
Reading the data must happen in a loop - as long as data is available. The call of read returns the number of bytes read.
ssize_t n;
while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[n] = '\0';
printf("%s", buffer);
}
To make sure that you don't save data beyond the end of the buffer, you can use sizeof(buffer) - 1 as the third argument to the read call.
Programm
So your program, slightly modified regarding the above points, could look like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
int pipefds[2];
char buffer[100];
if (argc < 2) {
fprintf(stderr, "usage: progname <filename>");
exit(EXIT_FAILURE);
}
if (pipe(pipefds) == -1) {
perror("PIPE ERROR");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == 0) {
FILE *fptr;
if ((fptr = fopen(argv[1], "r")) == NULL) {
perror("error opening file");
exit(EXIT_FAILURE);
}
char singleLine[150];
close(pipefds[0]);
while (fgets(singleLine, sizeof(singleLine), fptr)) {
write(pipefds[1], singleLine, strlen(singleLine));
}
int error = ferror(fptr);
fclose(fptr);
if (error) {
perror("error reading file");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} else if (pid > 0) {
close(pipefds[1]);
ssize_t n;
while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[n] = '\0';
printf("%s", buffer);
}
close(pipefds[0]);
}
return 0;
}
OK so I manage to write to the file char by char but it writes twice the numbers and it it still write it with spaces. Any advice and solution?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
extern int errno;
#define MAX_LEN 18
int main(int argc, char *argv[]) {
int fd[2], des, bytes, target;
char buffer[161];
int fdr, fdw; // file descriptors
char c;
fdr = open(argv[1], O_RDONLY); // open files
fdw = open("gg.txt", O_WRONLY | O_CREAT);
if (fdr < 0 || fdw < 0) {
perror("failed to open input or output files");
exit(EXIT_FAILURE);
}
while (read(fdr, &c, 1)) { // read/write a single char from/to the files
if (c != ' ' && c != EOF) {
if (write(fdw, &c, 1) != 1) {
perror("write() failed");
exit(EXIT_FAILURE);
}
} // echo char to stdout
}
close(fdr); // close the files
close(fdw);
exit(EXIT_SUCCESS);
}
EDIT SECTION
hey again,
i managed to read the file and write it to new one without spaces but i'm trying to insert the values to matrix but im getting an error trying to open the new file.
i have changed the permissions
fdw = open("gg.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
the function
void removeSpaces(int matrix[SIZE][SIZE],int fdr, int fdw) {
char c;
char matBuffer={0};
while (read(fdr, &c, 1)) // read/write a single char
{ // from/to the files
if (c != ' ') {
if (write(fdw, &c, 1) != 1) {
perror("write() failed");
exit(EXIT_FAILURE);
}
}
}
int i;
int j;
int k=0;
while(read(fdw, &matBuffer, 1))
{
for(i=0;i<SIZE;i++)
{
for(j=0;j<SIZE;j++)
{
matrix[i][j]=matBuffer-'0';
k++;
}
k=0;
}
}
}
The whole program
// C program to illustrate
// open system call
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#define MAX_LEN 18
#define SIZE 9
void removeSpaces(int matrix[SIZE][SIZE],int fdr, int fdw) {
char c;
char matBuffer={0};
while (read(fdr, &c, 1)) // read/write a single char
{ // from/to the files
if (c != ' ') {
if (write(fdw, &c, 1) != 1) {
perror("write() failed");
exit(EXIT_FAILURE);
}
}
}
int i;
int j;
int k=0;
while(read(fdw, &matBuffer, 1))
{
for(i=0;i<SIZE;i++)
{
for(j=0;j<SIZE;j++)
{
matrix[i][j]=matBuffer-'0';
k++;
}
k=0;
}
}
}
int is_safe(int matrix[9][9],int n, int r, int c)
{
int i,j;
//checking in row
for(i=0;i<9;i++)
{
//there is a cell with same value
if(matrix[r][i] == n)
return 0;
}
//checking column
for(i=0;i<SIZE;i++)
{
//there is a cell with the value equal to i
if(matrix[i][c] == n)
return 0;
}
//checking sub matrix
int row_start = (r/3)*3;
int col_start = (c/3)*3;
for(i=row_start;i<row_start+3;i++)
{
for(j=col_start;j<col_start+3;j++)
{
if(matrix[i][j]==n)
return 0;
}
}
return 1;
}
int main(int argc, char * argv[]) {
int pipe_descs[2];
int matrix[SIZE][SIZE];
int fdr, fdw; // file descriptors
int i,j;
/* if (pipe(pipe_descs) == -1) {
fprintf(stderr, "cannot open");
exit(1);
}
pid_t status = fork();
if(status ==0 )
{
}*/
fdr = open(argv[1], O_RDONLY); // open files
fdw = open("gg.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fdr < 0 || fdw < 0) { //validation for error
perror("failed to open input or output files");
exit(EXIT_FAILURE);
}
removeSpaces(matrix,fdr, fdw);
for(i=0; i<9; i++){ /* Iterate of each row */
for(j=0; j<9; j++){ /* In each row, go over each col element */
printf("%c ",matrix[i][j]); /* Print each row element */
}
printf("\n"); /* Finish a row, start a new line */
}
close(fdr); // close the files
close(fdw);
exit(EXIT_SUCCESS);
}
There are multiple problems in the code:
you do not test for read errors, read can return -1 for error, which would not stop the while loop.
testing c != EOF is meaningless. EOF is returned by getc() to indicate end of stream or input error, read indicates these conditions in its return value, c is always a byte value if read succeeded and returned 1.
gg.txt is not truncated by open with the given flags. Chances are you are overwriting the beginning of the file and for some reason the file is longer from previous attempts and still contains previously written data. You must also pass the mode bits for the file creation as the third argument to open. Use this:
// open the file for writing, truncate if it exists or create with
// read/write permission for user, read permission for group and others
fdw = open("gg.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
the comment // echo char to stdout does not seem to refer to any code.
Here is a corrected version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fdr, fdw; // file descriptors
char c;
fdr = open(argv[1], O_RDONLY); // open files
if (fdr < 0) {
fprintf(stderr, "failed to open input file %s: %s\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
// open the output file for writing, truncate if it exists or create with
// read/write permission for user, read permission for group and others
fdw = open("gg.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fdw < 0) {
fprintf(stderr, "failed to open output file %s: %s\n", "gg.txt", strerror(errno));
return EXIT_FAILURE;
}
// read/write a single char from/to the files
while (read(fdr, &c, 1) == 1) {
if (c != ' ') {
if (write(fdw, &c, 1) != 1) {
perror("write() failed");
return EXIT_FAILURE;
}
}
}
close(fdr); // close the files
close(fdw);
return EXIT_SUCCESS;
}
So I am working on a simple program in C but have been stuck on the copying portion. The program takes two filenames on the command line as arguments and copies the first to the second by using system calls. If the second file exists it asks the user if they want to overwrite, if not it creates it. However, my program when the user choices overwrite goes on infinitely.
Here is my code:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n;
char c;
int num;
if (argc != 3) {
printf("%d\n",argc);
printf("Error, you need to give 2 arguments. Such that [File to copy] [File to create].\n");
exit(1);
}
if (access(argv[1], F_OK) < 0) {
printf("File %s either does not exist or cannot be accessed.\n", argv[1]);
exit(1);
} else {
printf("file %s exists\n", argv[1]);
}
if (access(argv[2], F_OK) < 0) {
printf("File %s does not exist, but one will be created.\n", argv[1]);
fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700);
} else {
printf("file %s exists\n", argv[2]);
printf("Would you like to overwrite %s? (Type 1 for yes or 0 for no)\n", argv[2]);
scanf("%d%c", &num, &c); // use c to capture \n
if (num == 1) {
fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700);
} else {
if (num == 0) {
printf("Ok, the file will not be copied and the program will now exit.\n");
exit(1);
} else {
printf("I do not recognize this response, program will now be terminated.\n");
}
}
}
printf("step\n");
while ((n1 = read(fd1, buffer, 1024)) > 0) {
printf("step\n");
if(write(fd2, buffer, n1) != n1){
printf("step\n");
perror("Error writing file.");
printf("step\n");
exit(3);
}
printf("stepss\n");
}
close(fd1);
close(fd2);
}
The printf("step") is for debugging, but it only prints one. Meaning the program freezes up by the while loop. I can use stat(), open(), read(), write(), close(), and access(). Any ideas on what is wrong or how it can be done better would be appreciated!
Any ideas on what is wrong
Your fd1 never been assigned, so read(fd1, ...) returns an error.
Check return value of read and printf("%m\n") will print the details.
$ ./a.out a b
file a exists
file b exists
Would you like to overwrite b? (Type 1 for yes or 0 for no)
1
step
Bad file descriptor
I am trying to finish a program that can fork function a child process, and parent can get the input file (under same directory) , reverse the content of this file, then using pipe function pass to the child process. Child will read the message from pipe and generate an output file. I have finished fork, create pipe and reverse function. However I got stucked on write it to the pipe. I know there must some type confusion when i try to pass the parameter into the write function, Any hits would be appreciated.
Here is the Code I have so far:
#include <stdio.h>
#include <stdlib.h> //exit
#include <string.h>
#include <sys/types.h> //pid_t
#define READ_END 0
#define WRITE_END 1
int main(int argc, char *argv[]){
long loc;
FILE *in, *out;
char ch;
if (argc != 3)
{
printf("Usage %s message\n", argv[0]);
exit(EXIT_FAILURE);
}
int pipefd[2];
int pipe_return = pipe(pipefd);
if((in = fopen(argv[1], "rb")) == NULL) {
printf("Cannot open input file.\n");
exit(1);
}
if((out = fopen(argv[2], "wb"))==NULL) {
printf("Cannot open output file.\n");
exit(1);
}
if(pipe_return == -1)
{
printf("Unable to create pipe\n");
exit(EXIT_FAILURE);
}
pid_t return_from_fork = fork();
if (return_from_fork == -1)
{
printf("Unable to fork\n");
exit(EXIT_FAILURE);
}
else if (return_from_fork == 0) //this is a child
{
char msg;
close(pipefd[WRITE_END]);
int read_return = read(pipefd[READ_END], &msg, 1);
printf("read return:%d\n", read_return);
while(read_return > 0){
fputc(ch, out);
printf("%c",msg);
read_return = read(pipefd[READ_END], &msg, 1);
}
printf("child ends\n");
close(pipefd[READ_END]);
exit(EXIT_SUCCESS);
}
else if (return_from_fork > 0)
{
close(pipefd[READ_END]);
printf("this is parent\n");
fseek(in, 0L, SEEK_END);
loc = ftell(in);
while(loc >= 0L){
fseek(in, loc, SEEK_SET);
ch = fgetc(in);
printf("%c",ch);
int write_r = write(pipefd[WRITE_END], ch, 1);//here is the problem the printf() return -1
printf("%d",write_r);
loc--;
}
printf("\n");
close(pipefd[WRITE_END]);
wait(NULL);
printf("file successful generated.\n");
fcloseall();
exit(EXIT_SUCCESS);
}
}
And Here is the compile result:
zzz#ubuntu:~/Desktop/test$ gcc filereversecopy.c -o run
zzz#ubuntu:~/Desktop/test$ ./run src.txt out.txt
this is parent
�-1
-1e-1c-1n-1e-1t-1n-1e-1s-1 -1a-1 -1s-1i-1 -1s-1i-1h-1T-1
read return:0
child ends
file successful generated.
zzz#ubuntu:~/Desktop/test$
On the line you say is problem you are passing ch to write, and ch is type char. I'm sure you mean &ch instead. I bet if you change that write will return 1 instead of -1.
Also, you seek to the end to start reading, but when you seek to the end you are pointing at EOF. You need to start reading at the position before EOF. So after "fseek(in, 0L, SEEK_END); loc = ftell(in);" adding "loc--; fseek(in, loc, SEEK_SET);" makes it work.
I have to capture the stdout in a program and write that into a file...so I created a pipe. In the parent process, I captured the stdout in the pipe using dup() and I need to get this into a file...so I did a dup() in the child to get the captured file descriptor into the stdin. Now, how do I write this stdin into a file using fwrite()?
Isn't that doing things the hard way? All you need to do in the parent is use freopen() to connect stdout to the file of your choosing.
FILE *fp = freopen("/tmp/mylogfile", "w", stdout);
if (fp == 0)
error("...something went wrong opening the log file...\n");
The direct answer to your question is:
char buffer[32768];
ssize_t nbytes;
FILE *fp = fopen("/tmp/mylogfile", "w");
if (fp == 0)
error("....something went wrong opening my log file...\n");
while ((nbytes = fread(buffer, sizeof(char), sizeof(buffer), stdin)) > 0)
if (fwrite(buffer, sizeof(char), nbytes, fp) != nbytes)
error("...something went wrong writing to standard output...\n");
However, this is hardly necessary. You can improve the error handling in all sorts of ways; I'm simply assuming that 'error()' reports a message and does not return.
The easiest way is just to open the file and provide that as the child's stdout:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
switch (pid) {
case -1:
perror("fork");
return 1;
case 0:;
int new_out = open("output.txt", O_WRONLY | O_CREAT, 0666);
if (new_out == -1) {
perror("open");
return 1;
}
if (dup2(new_out, 1) == -1) {
perror("dup2");
return 1;
}
char* args[] = {"/bin/echo", "test output", 0};
execv(args[0], args);
perror("exec");
return 1;
default:;
int s;
if (waitpid(pid, &s, 0) == -1) {
perror("waitpid");
return 1;
}
if (WIFEXITED(s)) {
return WEXITSTATUS(s);
}
return 1;
}
}
You should capture into a byte or char buffer and the send that ot the fwrite.
When I say a buffer I mean an array or dynamically allocated block of bytes/chars.