I am writing a program in C that takes a a command line argument that represents the name of an output file. I then opened the file to write to it. The problem is that when I write something in the command line, it never shows up in the file I was writing to and any text in the file is erased. Here is the code I have for writing to the file from stdin.
(fdOut is the FILE * stream that was specified)
while(fread(buf, 1, 1024, stdin))
{
fwrite(buf, 1, 1024, fdOut);
}
try this code.
#include "stdio.h"
int main()
{
char buf[1024];
FILE *fdOut;
if((fdOut = fopen("out.txt","w")) ==NULL)
{ printf("fopen error!\n");return -1;}
while (fgets(buf, 1024, stdin) != NULL)
{
// int i ;
// for(i = 0;buf[i]!=NULL; ++i)
// fputc(buf[i],fdOut);
fputs(buf,fdOut);
// printf("write error\n");
}
fclose(fdOut);
return 0;
}
Note : use Ctrl+'D' to stop input.
let's assume that there is data coming in at stdin, d.g. you are using your program like:
cat infile.txt | ./myprog /tmp/outfile.txt
then data written with fwrite() will be buffered, so it won't appear immediately in the output file, but only when your OS decides that it's time to flush the buffer.
you can manually force writing to disk by using
fflush(fdOut);
(probably you don't want to do this all the time, as buffering allows for great speedups, esp when writing to slow media)
size_t nbytes;
while ((nbytes = fread(buf, 1, 1024, stdin)) > 0)
{
if (fwrite(buf, 1, nbytes, fdOut) != nbytes)
...handle short write...out of space?...
}
As you wrote it, you mishandle a short read, writing garbage that was not read to the output.
Related
I wrote a program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
int r;
char arr[] = "this is the string";
char str[20] = {'\0'};
fp = fopen("fwrite.txt", "w");
fwrite(arr, 1, sizeof(arr), fp);
fseek(fp, SEEK_SET, 0);
r = fread(str, 1, sizeof(arr), fp);
if(r == sizeof(arr))
printf("read successfully\n");
else
{
printf("read unsuccessfull\n");
exit(1);
}
printf("read = %d\n", r);
printf("%s\n", str);
fclose(fp);
return 0;
}
I am trying to read in this way but I am not able to do it. What is the problem here, is it that I should put &str[i] and run a loop for fread or will fread be able to put data in the str?
I am getting junk and I don't understand why?
The primary problem is that you have the arguments to fseek() backwards — you need the offset (0) before the whence (SEEK_SET). A secondary problem is that you attempt to read from a file open only for writing. A more minor issue in this context, but one that is generally very important, is that you don't error check the fopen() call. (It is relatively unlikely that this fopen() will fail, but funnier things have been known.) You should also check the fwrite() call (you already check the fread(), of course).
Fixing all these might lead to:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int rc = EXIT_SUCCESS;
int r;
const char file[] = "fwrite.txt";
char arr[] = "this is the string";
char str[20] = {'\0'};
FILE *fp = fopen(file, "w+b");
if (fp == 0)
{
fprintf(stderr, "Failed to open file %s for reading and writing\n", file);
rc = EXIT_FAILURE;
}
else
{
if (fwrite(arr, 1, sizeof(arr), fp) != sizeof(arr))
{
fprintf(stderr, "Failed to write to file %s\n", file);
rc = EXIT_FAILURE;
}
else
{
fseek(fp, 0, SEEK_SET);
r = fread(str, 1, sizeof(arr), fp);
if (r == sizeof(arr))
{
printf("read successful\n");
printf("read = %d bytes\n", r);
printf("read data [%s]\n", str);
}
else
{
printf("read unsuccessful\n");
rc = EXIT_FAILURE;
}
}
fclose(fp);
}
return rc;
}
Example run:
$ ./fi37
read successful
read = 19 bytes
read data [this is the string]
$
Note that this works in part because you write the null byte at the end of the output string to the file, and then read that back in. The file isn't really a text file if it contains null bytes. The b in "w+b" mode isn't really needed on Unix systems where there's no distinction between a binary and a text file. If you're writing null bytes to a file on Windows, you should use the b to indicate binary mode.
If you chose to, you could reduce the 'bushiness' (or depth of nesting) by not having a single return in the main() function. You could use return EXIT_FAILURE; and avoid an else and another set of braces. The code shown is careful to close the file if it was opened. In a general-purpose function, that's important. In main(), it is less critical since the exiting process will flush and close open files anyway.
You can't read in a file with the "w" mode for fopen, use "w+" instead.
"r" - Opens a file for reading. The file must exist.
"w" - Creates an empty file for writing. If a file with the same name already
exists, its content is erased and the file is considered as a new empty file.
"a" - Appends to a file. Writing operations, append data at the end of the
file. The file is created if it does not exist.
"r+" - Opens a file to update both reading and writing. The file must exist.
"w+" - Creates an empty file for both reading and writing.
"a+" - Opens a file for reading and appending.
After creating a function to grab stdin, stdout & stderr, I wanted to test it ..
Here is the test code:
int fd[3];
char *buf = calloc(200, sizeof(char));
FILE *stream;
pid_t pid;
pid = opencmd(fd, "/bin/echo", (char *[]){"/bin/echo", "hello!"});
stream = fdopen(fd[2], "r");
while (fgets(buf, 200, stream) != NULL)
printf("stderr: %s\n", buf);
fclose(stream);
stream = fdopen(fd[1], "r");
while (fgets(buf, 200, stream) != NULL)
printf("stdout: %s\n", buf);
fclose(stream);
free(buf);
closecmd(pid, fd);
This does not manage to work as intended. I spent an hour debugging and could not manage to trace the problem, but as far as I managed to go, I realized that using fdopen to start using the descriptors' streams does not work (for some reason), but using functions that work directly with file descriptors (such as write(2) & read(2)) works fine.
What might be the possible reason for this ?
this excerpt: (char *[]){"/bin/echo", "hello!"}); is missing the final NULL parameter – user3629249
void download(char *file)
{
int size = getsize(file);
printf("Got size %d\n", size);
sprintf(buff, "GET %s\n", file);
send(sockfd, buff, strlen(buff), 0);
rsize = recv(sockfd, buff, 1000, 0);
sscanf(buff, "%d", &resultcode);
printf("%s", buff);
if (strcmp(buff, "+OK\n") != 0)
{
printf("download failed\n");
}
FILE *dlfile = NULL;
if ((dlfile = fopen(file, "r")) != NULL)
{
dlfile = fopen(file, "w");
do
{
rsize = recv(sockfd, buff, 1000, 0);
for (int i = 0; i < rsize; i++)
{
fprintf(dlfile, "%c", buff[i]);
}
size = size - rsize;
} while (size != 0);
}
fclose(dlfile);
}
I am trying to make the download function print out contents of file user typed, then save it to their current directory. I did a debug line printf("%s", buff); and it prints out +OK\n(filename). It is supposed to print out +OK\n. It also prints out download failed then a segmentation fault error. What am I missing?
Several things going on here. First, recv and send basically operate on arrays of bytes so they do not know about line endings and such. Also note that recv is not guaranteed to fill the buffer - it generally reads what is available up to the limit of the buffer. For your strcmp against "+OK\n", you could use strncmp with a length of 4 but that is a bit direct (see below). Next note that the buff string is not null terminated by recv so your printf could easily crash.
When you go in to your loop, the buffer already has part of the rest of your I/O in it. May include other fields or parts of the file. You need to process it as well. It is not clear to me what getsize does - but using that size to drive your loop seems off. Also, your loop to fprintf the values can be replaced by a call to fwrite.
Overall, you need to properly buffer and then parse the incoming stream of data. If you want to do it yourself, you could look at fdopen to get a FILE object.
For example, I am able to write the contents of an input file to and output file with:
char buffer[1024]; // character buffer
char userInput[1024]; // for user input
char *p;
char *q;
int n;
int input_file1; // file descriptor for file 1
int input_file2; // file descriptor for file 2
int output_file; // file descriptor for output_file
while((n = read(input_file1, buffer, sizeof(buffer))) > 0)
{
progress("entered first while loop");
if((write(output_file, buffer, n)) < 0)
{
progress("couldn't write to output within while loop 1");
perror(argv[3]);
close(input_file1);
close(input_file2);
close(output_file);
exit(1);
}
}
I also have some user input:
printf("\nEnter text then hit enter: ");
q = fgets(userInput, sizeof(userInput), stdin);
I want to append the user input to the same output file using write();
How can I do this?
----- update ---- works with
if(strcmp(argv[1], "-") == 0) // use standard-in for input file 1
{
progress("file 1 detected as \"-\": using std input");
p = fgets(userInput, sizeof(userInput), stdin);
if (write(output_file, userInput, sizeof(p)) < 0) {
progress("write from stdin to output file failed");
perror(argv[4]);
exit(1);
}
progress("wrote from stdin to output file");
}
just you make the same thing. but you do not have to close the file in the first while.
and the get the input from the user (stdin) and then write it to the file with write() function
q = fgets(userInput, sizeof(userInput), stdin);
write(output_file, userInput, strlen(userInput));
close(output_file);
Assuming you have already opened the output_file for writing (and possibly written to it):
#define MAX 120
char buffer[MAX];
int len = sprintf(buffer, "Whatever you want to print in %d characters.\n", MAX);
if (write(output_file, buffer, len) < 0) {
perror("Cannot write to file.");
exit(1);
}
The write() function has the prototype :
ssize_t write(int fildes, const void *buf, size_t nbyte);
On a regular file or other file capable of seeking, the actual writing of data shall proceed from the position in the file indicated by the file offset associated with fildes. Before successful return from write(), the file offset shall be incremented by the number of bytes actually written. On a regular file, if this incremented file offset is greater than the length of the file, the length of the file shall be set to this file offset.
On a file not capable of seeking, writing shall always take place starting at the current position. The value of a file offset associated with such a device is undefined.
If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file prior to each write and no intervening file modification operation shall occur between changing the file offset and the write operation.
Just open() the ouput file with mode O_APPEND
output_file = open("output", O_WRONLY | O_APPEND | O_CREAT);
this way, write will append to the file.
write(output_file, userInput, strlen(userInput));
I am using following code snippet in C to copy a file:
#define CHUNK 4096
char buf[CHUNK];
FILE *file , *out;
size_t nread;
file = fopen("test", "rb");
out = fopen("out", "wb");
if (file) {
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
fwrite(buf, 1, nread, out);
if (ferror(file)) {
/* Not getting error here */
}
fclose(file);
fclose(out);
}
My file is very large (200 MB), I have to handle errors if file is moved or removed while reading, writing is in progress. How can I do that?
Let me clear it tad more, Any how I will get access to path by some wifi means. So if wifi will be disconnected then how I'll get the error..
If the count bytes written is different from the nread parameter this would indicate an error, so:
if(fwrite(buf, 1, nread, out) != nread) {
// error handling
}
Under windows you could lock the file using _lock_file(); to prevent other processes from deleting the file:
#include <stdio.h>
if (file) {
// lock file
_lock_file(file);
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
fwrite(buf, 1, nread, out);
// unlock the file
_unlock_file(file);
fclose(file);
fclose(out);
}
You should probably open your output file in write mode, i.e. "wb".
How to handle errors: check return values of the I/O functions, and try to deal with the errors. You can use feof() and ferror() to analyze what went wrong. Make sure to always do some I/O before calling either of them (don't try to detemine EOF before reading).