I'm learning how to write and read files in C, and I wrote a text using this code
FILE *f = fopen("testingText.txt", "w");
char *text = "This is text1...";
fwrite(text, sizeof(char), strlen(text), f );
fclose(f);
and when I read the content of this file and print it using this code
FILE *f = fopen("testingText.txt", "r");
fseek(f, 0, SEEK_END);
unsigned int size = ftell(f);
fseek(f , 0, SEEK_SET);
char *content = (char *)malloc(size);
fread(content, sizeof(char), size, f);
printf("File content is...\n%s", content);
free(content);
fclose(f);
it gives the result with strange things like these
File content is...
This is text1...Path=C:*┬#æ╩eò*
and when I run the code again it gives different strange things.
There is no null terminator in the file so you'll need to add that manually before printing what you've read from the file.
Example:
char *content = malloc(size + 1); // +1 for the null terminator
size_t chars_read = fread(content, 1, size, f); // store the returned value
content[chars_read] = '\0'; // add null terminator
printf("File content is...\n%s\n", content); // now ok to print
The following line is wrong:
printf("File content is...\n%s", content);
Using printf with the %s conversion format specifier requires a null-terminated string. However, your string is not null-terminated.
In order to print a sequence of characters that is not null-terminated, you can write the following instead:
printf( "File content is...\n%.*s", (int)size, content );
Or you can add a terminating null character manually, with the following line:
content[size] = '\0';
However, this will write to the memory buffer content out of bounds, because you did not allocate any space for the null terminating character. Therefore, you should allocate one additional byte in the malloc function call.
Another problem is that using ftell is not a reliable way to determine the length of the file. The ISO C standard does not guarantee that this will work.
For example, on Microsoft Windows, this will give you the length of the file in binary mode (even when the file is opened in text mode). However, the length of the file in text mode is different, because \r\n line endings get translated to \n on Microsoft Windows.
Therefore, if you want to read the content of a text file of unknown length, it would probably be better to read one line at a time in a loop, using the function fgets:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
FILE *fp;
char line[100];
//attempt to open file
fp = fopen( "testingText.txt", "r" );
//verify that file is open
if ( fp == NULL )
{
fprintf( stderr, "error opening file!\n" );
exit( EXIT_FAILURE );
}
printf( "File content is...\n" );
//print one line per loop iteration
while ( fgets( line, sizeof line, fp ) != NULL )
{
//the following code will work even if "fgets" only
//reads a partial line, due to the input buffer not
//being large enough
//print the line to standard output
fputs( line, stdout );
}
//cleanup
fclose( fp );
}
Related
I'm using the fopen with fread for this:
FILE *fp;
if (fopen_s(&fp, filePath, "rb"))
{
printf("Failed to open file\n");
//exit(1);
}
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
char buffer = (char)malloc(sizeof(char)*size);
if (!buffer)
{
printf("Failed to malloc\n");
//exit(1);
}
int charsTransferred = fread(buffer, 1, size, fp);
printf("charsTransferred = %d, size = %d\n", charsTransferred, strlen(buffer));
fclose(fp);
I'm not getting the file data in the new file. Here is a comparison between the original file (right) and the one that was sent over the network (left):
Any issues with my fopen calls?
EDIT: I can't do away with the null terminators, because this is a PDF. If i get rid of them the file will corrupt.
Be reassured: the way you're doing the read ensures that you're reading all the data.
you're using "rb" so even in windows you're covered against CR+LF conversions
you're computing the size all right using ftell when at the end of the file
you rewind the file
you allocate properly.
BUT you're not storing the right variable type:
char buffer = (char)malloc(sizeof(char)*size);
should be
char *buffer = malloc(size);
(that very wrong and you should correct it, but since you successfully print some data, that's not the main issue. Next time enable and read the warnings. And don't cast the return value of malloc, it's error-prone specially in your case)
Now, the displaying using printf and strlen which confuses you.
Since the file is binary, you meet a \0 somewhere, and printf prints only the start of the file. If you want to print the contents, you have to perform a loop and print each character (using charsTransferred as the limit).
That's the same for strlen which stops at the first \0 character.
The value in charsTransferred is correct.
To display the data, you could use fwrite to stdout (redirect the output or this can crash your terminal because of all the junk chars)
fwrite(buffer, 1, size, stdout);
Or loop and print only if the char is printable (I'd compare ascii codes for instance)
int charsTransferred = fread(buffer, 1, size, fp);
int i;
for (i=0;i<charsTransferred;i++)
{
char b = buffer[i];
putchar((b >= ' ') && (b < 128) ? b : "-");
if (i % 80 == 0) putchar('\n'); // optional linefeed every now and then...
}
fflush(stdout);
that code prints dashes for characters outside the standard printable ASCII-range, and the real character otherwise.
There are no compile errors just functionality
I was attempting to make a simple XOR crypter in c. I found out that the crypting part is not a problem because when the XOR function is used twice on the same string it returns the the exact string I sent back. The problem I believe is therefore not with the crypting part, I believe that the problem occurs when writing the file.
Function the error is within
int xorFile (char *infile, char *outfile) {
FILE *in,
*out;
long lSize;
char *buffer;
in = fopen ( infile , "rb" );
out = fopen(outfile, "wb");
if( !in ) perror(infile),exit(1);
fseek( in , 0L , SEEK_END);
lSize = ftell( in );
rewind( in );
/* allocate memory for entire content */
buffer = (char*)calloc( 1, lSize+1 );
if( !buffer ) fclose(in),fputs("memory alloc fails",stderr),exit(1);
/* copy the file into the buffer */
if( 1!=fread( buffer , lSize, 1 , in) )
fclose(in),free(buffer),fputs("entire read fails",stderr),exit(1);
/* do your work here, buffer is a string contains the whole text */
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
fclose(in);
free(buffer);
fclose(out);
return 0;
}
What I believe causes the error
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
Full Program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define XOR_KEY 0x6F
int xorFile (char *infile, char *outfile) {
FILE *in,
*out;
long lSize;
char *buffer;
in = fopen ( infile , "rb" );
out = fopen(outfile, "wb");
if( !in ) perror("blah.txt"),exit(1);
fseek( in , 0L , SEEK_END);
lSize = ftell( in );
rewind( in );
/* allocate memory for entire content */
buffer = (char*)calloc( 1, lSize+1 );
if( !buffer ) fclose(in),fputs("memory alloc fails",stderr),exit(1);
/* copy the file into the buffer */
if( 1!=fread( buffer , lSize, 1 , in) )
fclose(in),free(buffer),fputs("entire read fails",stderr),exit(1);
/* do your work here, buffer is a string contains the whole text */
int i;
for(i=0;buffer[i]!='\0';i++) {
fputc(buffer[i] ^ XOR_KEY,out);
}
fclose(in);
free(buffer);
fclose(out);
return 0;
}
int main (int argc, char *argv[]) {
if (argc <= 2) {
fprintf (stderr, "Usage: %s [IN FILE] [OUT FILE]\n" , argv[0]) ;
exit (1);
}
xorFile (argv[1], argv[2]) ;
}
Tested causes
Checked on multiple OS's
Checked on different file formats
Checked on different privileges
Checked on different compilers as well(ran out of things to test)
Additional infomation
When I encrypted a copy of the source file and decrypted it, all that remained was #include <std
The problem you're experiencing is caused by your loop exiting prematurely. The following test will stop as soon as it encounters a null byte:
for(i=0;buffer[i]!='\0';i++)
To encrypt the entire file, this needs to be changed to:
for(i=0;i<lSize;i++)
This will be a problem not only for non-text files, but also for decrypting, since the encryption process will introduce zero bytes for any characters that match your XOR_KEY. For instance, if your XOR_KEY is 0x69, which is an ascii 'i', your encrypted file will contain a zero byte in place of each 'i'. When decrypting it, it will cut the file off at the first such character, which explains what you've been seeing. This will correct that.
buffer[i] ^= XOR_KEY;
fputc(buffer[i] ^ XOR_KEY,out);
First, the program looks at the character in buffer[i], XORs it, and stores the XORed character back in buffer[i].
Then, it looks at the character in buffer[i] (which is now XORed), XORs it again, and writes that to out.
So the character that gets written to out has been XORed twice - so it's just the original character.
I'm using fscanf function in a c code to read a file contains 1 line of words separated by white spaces, but for example if the first word is 1234, then when I print it the output is 234, however the other words in the file are read correctly, any ideas?
FILE* file = fopen(path, "r");
char arr = getc(file);
char temp[20];
while(fscanf(file,"%s",temp)!= EOF && i<= column)
{
printf("word %d: %s\n",i, temp);
}
char arr = getc(file);
Probably above line is causing to loose the first char.
Here is the posted code, with my comments
When asking a question about a run time problem,
post code that cleanly compiles, and demonstrates the problem
FILE* file = fopen(path, "r");
// missing check of `file` to assure the fopen() was successful
char arr = getc(file);
// this consumed the first byte of the file, (answers your question)
char temp[20];
while(fscanf(file,"%s",temp)!= EOF && i<= column)
// missing length modifier. format should be: "%19s"
// 19 because fscanf() automatically appends a NUL byte to the input
// 19 because otherwise the input buffer could be overrun,
// resulting in undefined behaviour and possible seg fault event
// should be checking (also) for returned value == 1
// this will fail as soon as an `white space` is encountered
// as the following call to fscanf() will not read/consume the white space
// suggest a leading space in the format string to consume white space
{
printf("word %d: %s\n",i, temp);
// the variable 'i' is neither declared nor modified
// within the scope of the posted code
}
char arr = getc(file);
reads the first character from the file stream and iterates the file stream file
you can use rewind(file) after char arr = getc(file) to reset your file stream to the beginning.
Other example:
#include <stdio.h>
int main(void)
{
FILE *f;
FILE *r;
char str[100];
size_t buf;
memset(str, 0, sizeof(str));
r = fopen("in.txt", "r");
f = fopen("out.txt", "w+b");
fscanf(r, "%s", str);
rewind(r); // without this, the first char won't be written
buf = fread(str, sizeof(str), 1, r);
fwrite(str, sizeof(str), 1, f);
fclose(r);
fclose(f);
return (0);
}
i have a c project and i have serious problem , i want to open file and replace line number nb (nb is an int) with "*" . this is my code could some one help me please ? it show me the word i want to replace that's mean that the pointer is pointing on the wanted line but nothing happen .help me please
#include <stdio.h>
int main( void )
{
FILE * f;
char ch[1024];
int i, nb;
i = 0;
scanf( "%d", &nb ) ;
f = fopen( "dict.txt", "r+t" );
while( i < nb )
{
fscanf( f, "%s", ch ) ;
i++;
}
printf( "%s", ch );
fprintf( f, "%s", "****" );
fclose( f );
}
You've opened the file for reading and writing. According to the MSDN man page for fopen (I am assuming from the r+t mode on the file that you are using Visual Studio):
When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there is no EOF, you must use an intervening call to a file positioning function. The file positioning functions are fsetpos, fseek, and rewind.
Some other things to keep in mind:
When fscanf reads a string with %s, it reads only one word at a time, not a whole line. It is easier to read whole lines of input with fgets than with fscanf.
A file consists of a stream of bytes. If the line you want to replace is 47 characters long, then fprintf(f, "%s", "****") will only replace the first four bytes in the line.
That means that if you want to replace line #nb, you will need to read in the line, figure out how long it is, then seek back to the beginning of the line and print out the correct number of asterisks.
Try something like this instead:
#include <stdio.h>
#include <string.h>
int main()
{
FILE * f;
char ch[1024];
int i,nb ;
fpos_t beginning_of_line;
i=0;
scanf("%d",&nb) ;
f = fopen("dict.txt", "r+t");
while (i<nb)
{
fgetpos(f, &beginning_of_line);
fgets(ch, 1024, f);
i++;
}
fseek(f, beginning_of_line, SEEK_SET); // return to beginning of line
for (i = 0; ch[i] != '\n'; ++i) {
fputc('*', f);
}
fclose(f);
}
I have a text file named test.txt
I want to write a C program that can read this file and print the content to the console (assume the file contains only ASCII text).
I don't know how to get the size of my string variable. Like this:
char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
while (fscanf(file, "%s", str)!=EOF)
printf("%s",str);
fclose(file);
}
The size 999 doesn't work because the string returned by fscanf can be larger than that. How can I solve this?
The simplest way is to read a character, and print it right after reading:
int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
c is int above, since EOF is a negative number, and a plain char may be unsigned.
If you want to read the file in chunks, but without dynamic memory allocation, you can do:
#define CHUNK 1024 /* read 1024 bytes at a time */
char buf[CHUNK];
FILE *file;
size_t nread;
file = fopen("test.txt", "r");
if (file) {
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
fwrite(buf, 1, nread, stdout);
if (ferror(file)) {
/* deal with error */
}
fclose(file);
}
The second method above is essentially how you will read a file with a dynamically allocated array:
char *buf = malloc(chunk);
if (buf == NULL) {
/* deal with malloc() failure */
}
/* otherwise do this. Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
/* as above */
}
Your method of fscanf() with %s as format loses information about whitespace in the file, so it is not exactly copying a file to stdout.
There are plenty of good answers here about reading it in chunks, I'm just gonna show you a little trick that reads all the content at once to a buffer and prints it.
I'm not saying it's better. It's not, and as Ricardo sometimes it can be bad, but I find it's a nice solution for the simple cases.
I sprinkled it with comments because there's a lot going on.
#include <stdio.h>
#include <stdlib.h>
char* ReadFile(char *filename)
{
char *buffer = NULL;
int string_size, read_size;
FILE *handler = fopen(filename, "r");
if (handler)
{
// Seek the last byte of the file
fseek(handler, 0, SEEK_END);
// Offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
// go back to the start of the file
rewind(handler);
// Allocate a string that can hold it all
buffer = (char*) malloc(sizeof(char) * (string_size + 1) );
// Read it all in one operation
read_size = fread(buffer, sizeof(char), string_size, handler);
// fread doesn't set it so put a \0 in the last position
// and buffer is now officially a string
buffer[string_size] = '\0';
if (string_size != read_size)
{
// Something went wrong, throw away the memory and set
// the buffer to NULL
free(buffer);
buffer = NULL;
}
// Always remember to close the file.
fclose(handler);
}
return buffer;
}
int main()
{
char *string = ReadFile("yourfile.txt");
if (string)
{
puts(string);
free(string);
}
return 0;
}
Let me know if it's useful or you could learn something from it :)
Instead just directly print the characters onto the console because the text file maybe very large and you may require a lot of memory.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f;
char c;
f=fopen("test.txt","rt");
while((c=fgetc(f))!=EOF){
printf("%c",c);
}
fclose(f);
return 0;
}
Use "read()" instead o fscanf:
ssize_t read(int fildes, void *buf, size_t nbyte);
DESCRIPTION
The read() function shall attempt to read nbyte bytes from the file associated with the open file descriptor, fildes, into the buffer pointed to by buf.
Here is an example:
http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html
Working part from that example:
f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
write(1,l,n);
An alternate approach is to use getc/putc to read/write 1 char at a time. A lot less efficient. A good example: http://www.eskimo.com/~scs/cclass/notes/sx13.html
You can use fgets and limit the size of the read string.
char *fgets(char *str, int num, FILE *stream);
You can change the while in your code to:
while (fgets(str, 100, file)) /* printf("%s", str) */;
Two approaches leap to mind.
First, don't use scanf. Use fgets() which takes a parameter to specify the buffer size, and which leaves any newline characters intact. A simple loop over the file that prints the buffer content should naturally copy the file intact.
Second, use fread() or the common C idiom with fgetc(). These would process the file in fixed-size chunks or a single character at a time.
If you must process the file over white-space delimited strings, then use either fgets or fread to read the file, and something like strtok to split the buffer at whitespace. Don't forget to handle the transition from one buffer to the next, since your target strings are likely to span the buffer boundary.
If there is an external requirement to use scanf to do the reading, then limit the length of the string it might read with a precision field in the format specifier. In your case with a 999 byte buffer, then say scanf("%998s", str); which will write at most 998 characters to the buffer leaving room for the nul terminator. If single strings longer than your buffer are allowed, then you would have to process them in two pieces. If not, you have an opportunity to tell the user about an error politely without creating a buffer overflow security hole.
Regardless, always validate the return values and think about how to handle bad, malicious, or just malformed input.
You can use getline() to read your text file without worrying about large lines:
getline() reads an entire line from stream, storing the address of the buffer containing the text into *lineptr. The buffer is null-terminated and includes the newline character, if one was found.
If *lineptr is set to NULL before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.
bool read_file(const char *filename)
{
FILE *file = fopen(filename, "r");
if (!file)
return false;
char *line = NULL;
size_t linesize = 0;
while (getline(&line, &linesize, file) != -1) {
printf("%s", line);
free(line);
}
free(line);
fclose(file);
return true;
}
You can use it like this:
int main(void)
{
if (!read_file("test.txt")) {
printf("Error reading file\n");
exit(EXIT_FAILURE);
}
}
I use this version
char* read(const char* filename){
FILE* f = fopen(filename, "rb");
if (f == NULL){
exit(1);
}
fseek(f, 0L, SEEK_END);
long size = ftell(f)+1;
fclose(f);
f = fopen(filename, "r");
void* content = memset(malloc(size), '\0', size);
fread(content, 1, size-1, f);
fclose(f);
return (char*) content;
}
You could read the entire file with dynamic memory allocation, but isn't a good idea because if the file is too big, you could have memory problems.
So is better read short parts of the file and print it.
#include <stdio.h>
#define BLOCK 1000
int main() {
FILE *f=fopen("teste.txt","r");
int size;
char buffer[BLOCK];
// ...
while((size=fread(buffer,BLOCK,sizeof(char),f)>0))
fwrite(buffer,size,sizeof(char),stdout);
fclose(f);
// ...
return 0;
}