Reverse file text - c

I'm trying to make a program that uses fgets to take the text from a preexisting file, invert it and then write it to another file. This is the code I've written so far:
#include <stdio.h>
#include <string.h>
int main()
{
int c, d;
FILE *file1, *file2;
char string [100], *begin, *end, temp;
file1 = fopen("StartingFile.txt", "rt");
if (file1 == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fgets(string, 100, file1);
fclose (file1);
begin = string;
end = begin + strlen(string) - 1;
while (end > begin)
{
temp = *begin;
*begin = *end;
*end = temp;
++begin;
--end;
}
file2 = fopen("FinalFile.txt", "wt");
fprintf (file2, "%s", string);
fclose (file2);
printf ("%s\n", string);
return 0;
}
It works fine if the text in the preexisting file is all in one line, but if it has more than one line, only the first one is inverted and written to the new file. I think that fgets can only read one line, so I think I'll have to use a loop, but I'm having trouble implementing it. Can someone give me a hand? Thanks in advance!

To read each line separately from file use fgets in while loop as below,
while(fgets(string, sizeof(string), file1) != NULL)
{
...
}
fclose(file1);
Inside the loop operate on each line to reverse it.

Your code has quite a few logical errors in it. I would recommend using other f* methods instead.
If you want an easy solution, open the file, determine its length, create two buffers of the size of the file, fill the first buffer with the file's contents and then do a loop to copy the reverse to the other buffer, then write that buffer back. Roughly that would look like this:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *file;
file = fopen("StartingFile.txt", "rt");
if (file == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fseek(file, 0, SEEK_END); // move file pointer to end of file
long size = ftell(file); // file pointer position == character count in file
fseek(file, 0, SEEK_SET); // move back to beginning of file
char* buffer = malloc(size * sizeof(char));
fread(buffer, sizeof(char), size, file) // read file contents to buffer
for(long i = 0; i < size/2; ++i)
{
buffer[i] = buffer[size-i-1];
}
fseek(file, 0, SEEK_SET); // The fread set the file pointer to the end so we need to put it to the front again.
fwrite(buffer, sizeof(char), size, file); // Write reverted content
delete buffer;
fclose (file);
}
I haven't tested it and it may contain a few errors since I haven't programmed in C for some time. The only reason to still be programming in C anyways is efficiency and if you want your program to be efficient, the two buffer solution isn't the best either. At least not in terms of memory usage.
I highly recommend getting familiar with all the functions available in C (stdio and so on) cplusplus.com is a great reference for that.
Regards, Xaser

Related

Dynamically allocating memory to an array and reading a large text file

I've had a look at some other similar questions and examples but I'm stumped. My goal is to open a very large text file (novel sized), allocate memory to an array, and then store the text into that array so I'm able to do further processing in the future.
This is my current code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINELEN 74
int main(void) {
FILE *file;
char filename[] = "large.txt";
int count = 0, i = 0, len;
/* Open the file */
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file");
return -1;
}
/* Get size of file for memory allocation */
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
/* Allocate memory to the array */
char *text_array = (char*)malloc(size*sizeof(char));
/* Store the information into the array */
while(fgets(&text_array[count], LINELEN, file) != NULL) {
count++;
}
len = sizeof(text_array) / sizeof(text_array[0]);
while(i<len) {
/* printf("%s", text_array); */
i++;
}
printf("%s", text_array);
/* return array */
return EXIT_SUCCESS;
}
I was expecting to have a large body of text printed from text_array at the bottom. Instead I get a garbled mess of random characters much smaller than the body of text I was hoping for. What am I doing wrong? I suspect it has something to do with my memory allocation but don't know what.
Any help is much appreciated.
There's no need to call fgets() in a loop. You know how big the file is, just read the entire thing into text_array with one call:
fread(text_array, 1, size, file);
However, if you want to treat text_array as a string, you need to add a null terminator. So you should add 1 when calling malloc().
Another problem is len = sizeof(text_array) / sizeof(text_array[0]). text_array is a pointer, not an array, so you can't use sizeof to get the amount of space it uses. But you don't need to do that, since you already have the space in the size variable.
There's no need to print text_array in a loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINELEN 74
int main(void) {
FILE *file;
char filename[] = "large.txt";
int count = 0, i = 0, len;
/* Open the file */
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file");
return -1;
}
/* Get size of file for memory allocation */
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
/* Allocate memory to the array */
char *text_array = (char*)malloc(size*sizeof(char) + 1);
/* Store the information into the array */
fread(text_array, 1, size, file);
text_array[size] = '\0';
printf("%s, text_array);
/* return array */
return EXIT_SUCCESS;
}
This part
while(fgets(&text_array[count], LINELEN, file) != NULL) {
count++;
}
is problematic.
If the loop is un-rolled it's "kind of like":
fgets(&text_array[0], LINELEN, file)
fgets(&text_array[1], LINELEN, file)
fgets(&text_array[2], LINELEN, file)
So you only advance the fgetsdestination buffer by a single char between each fgets call. If we assume the fgets reads more than a single character, the second fgets overwrites data from the first fgets. The third fgets overwrites data from the second and so on.
You need to advance the buffer with as many characters as fgets actually read or use another way of reading, e.g. fread.

how to write one binary file to another in c

I have a few binary files that I want to write into an output file.
So I wrote this function using a char as a buffer naively thinking it would work.
//Opened hOutput for writing, hInput for reading
void faddf(FILE* hOutput, FILE* hInput) {
char c;
int scan;
do{
scan = fscanf(hInput, "%c", &c);
if (scan > 0)
fprintf(hOutput, "%c", c);
} while (scan > 0 && !feof(hInput));
}
Executing this function gives me an output of the few readable char's in the beginning binary file. So I tried it this way:
void faddf(FILE* hOutput, FILE* hInput) {
void * buffer;
int scan;
buffer = malloc(sizeof(short) * 209000000);
fread(buffer, sizeof(short), 209000000, hInput);
fwrite(buffer, sizeof(short), 209000000, hOutput);
free(buffer);
}
This "works" but is only works when the file is smaller then my "magic number" Is there a better way?
Although your new code (in the answer) is much better than the old code, it can still be improved and simplified.
Specifically, you can avoid any memory problems by copying the file in chunks.
void faddf( FILE *fpout, FILE *fpin )
{
char buffer[4096];
size_t count;
while ( (count = fread(buffer, 1, sizeof buffer, fpin)) > 0 )
fwrite(buffer, 1, count, fpout);
}
You should avoid reading bytes per byte. Use the fgets() function instead of fscanf().
Please refer to : Man fgets() (for Windows)
When you open both files next to each other (input one / output one), you're saying that the output file only contains readable characters... But can your text editor display unreadable characters on the input one ?
I should not have asked the question in the first place but here is how I ended up doing it:
void faddf(FILE* hOutput, FILE* hInput) {
void * buffer;
int scan,size;
size_t read;
//get the input file size
fseek(hInput, 0L, SEEK_END);
size = ftell(hInput);
fseek(hInput, 0L, SEEK_SET);
//place the get space
buffer = malloc(size);
if (buffer == NULL)exit(1);//should fail silently instead
//try to read everything to buffer
read = fread(buffer, 1, size, hInput);
//write what was read
fwrite(buffer, 1, read, hOutput);
//clean up
free(buffer);
}

program wouldn't stop reading file

I was experimenting with writing a program that would reverse the contents of a file.
So, giving the inputfile with the content "abc" it should make a file with a content "cba".
Unfortunately, it doesn't work and I don't understand why.
Could you guys please help me?
Thanks
EDIT: i forgot to mention that it was a school assignment - and we have to use functions like lseek and open - Please dont posr me that I should've used fgetc anfd other functions :)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void reverse_file(char * in, char * out)
{
int infile, outfile;
infile = open(in, O_RDONLY);
outfile = open(out, O_WRONLY);
char buffer;
char end = EOF;
write(outfile, &end, sizeof(char));
do
{
// seek to the beginning of a file
read(infile, &buffer, sizeof(char));
// printf("the code of a character %d\n", buffer); // returns 10 instead of EOF
lseek(outfile, 0, SEEK_SET);
write(outfile, &buffer, sizeof(char));
} while (buffer != EOF);
close(outfile);
close(infile);
}
int main()
{
reverse_file("tt", "testoutput");
return 0;
}
read returns the number of bytes it reads. To make your loop stop when you reach the end of the file, change your condition to the return value of read.
int read_ret;
do
{
// seek to the beginning of a file
read_ret = read(infile, &buffer, sizeof(char));
// printf("the code of a character %d\n", buffer); // returns 10 instead of EOF
lseek(outfile, 0, SEEK_SET);
write(outfile, &buffer, sizeof(char));
} while (read_ret > 0);
When read reach the end of the file and returns zero, it does not set *buffer. That is why your loop never stop.
Your current code (outside the fact that the test for the end of file is wrong), will make a file of one char, because write overwrite the data present in the file at the current position (unless it's at the end, where it would append).
Actually, to reverse the file, you should read it starting from the end.
struct stat instat;
int pos;
fstat(infile, &instat);
pos = instat.st_size - 1;
do
{
// seek backward in the input file, starting from the end
lseek(infile, SEEK_SET, pos);
read(infile, &buffer, sizeof(char));
write(outfile, &buffer, sizeof(char));
} while (pos-- > 0);
(Reading char by char is very ineficient with the unix read and write system calls, so as a second step, you should consider using the C primitives (fopen, fread, fwrite), or do some buffered reads and writes with the unix system calls.)
See:
open
read
write
lseek
fstat
You need to read to read the whole input file and then write it out. Don't try to do it char by char and don't use lseek.

In C, how should I read a text file and print all strings

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;
}

Correct way to read a text file into a buffer in C? [duplicate]

This question already has answers here:
How to read the content of a file to a string in C?
(12 answers)
Closed 5 years ago.
I'm dealing with small text files that i want to read into a buffer while i process them, so i've come up with the following code:
...
char source[1000000];
FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
while((symbol = getc(fp)) != EOF)
{
strcat(source, &symbol);
}
fclose(fp);
}
...
Is this the correct way of putting the contents of the file into the buffer or am i abusing strcat()?
I then iterate through the buffer thus:
for(int x = 0; (c = source[x]) != '\0'; x++)
{
//Process chars
}
char source[1000000];
FILE *fp = fopen("TheFile.txt", "r");
if(fp != NULL)
{
while((symbol = getc(fp)) != EOF)
{
strcat(source, &symbol);
}
fclose(fp);
}
There are quite a few things wrong with this code:
It is very slow (you are extracting the buffer one character at a time).
If the filesize is over sizeof(source), this is prone to buffer overflows.
Really, when you look at it more closely, this code should not work at all. As stated in the man pages:
The strcat() function appends a copy of the null-terminated string s2 to the end of the null-terminated string s1, then add a terminating `\0'.
You are appending a character (not a NUL-terminated string!) to a string that may or may not be NUL-terminated. The only time I can imagine this working according to the man-page description is if every character in the file is NUL-terminated, in which case this would be rather pointless. So yes, this is most definitely a terrible abuse of strcat().
The following are two alternatives to consider using instead.
If you know the maximum buffer size ahead of time:
#include <stdio.h>
#define MAXBUFLEN 1000000
char source[MAXBUFLEN + 1];
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
size_t newLen = fread(source, sizeof(char), MAXBUFLEN, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
fclose(fp);
}
Or, if you do not:
#include <stdio.h>
#include <stdlib.h>
char *source = NULL;
FILE *fp = fopen("foo.txt", "r");
if (fp != NULL) {
/* Go to the end of the file. */
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
long bufsize = ftell(fp);
if (bufsize == -1) { /* Error */ }
/* Allocate our buffer to that size. */
source = malloc(sizeof(char) * (bufsize + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(source, sizeof(char), bufsize, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
source[newLen++] = '\0'; /* Just to be safe. */
}
}
fclose(fp);
}
free(source); /* Don't forget to call free() later! */
Yes - you would probably be arrested for your terriable abuse of strcat !
Take a look at getline() it reads the data a line at a time but importantly it can limit the number of characters you read, so you don't overflow the buffer.
Strcat is relatively slow because it has to search the entire string for the end on every character insertion.
You would normally keep a pointer to the current end of the string storage and pass that to getline as the position to read the next line into.
If you're on a linux system, once you have the file descriptor you can get a lot of information about the file using fstat()
http://linux.die.net/man/2/stat
so you might have
#include <unistd.h>
void main()
{
struct stat stat;
int fd;
//get file descriptor
fstat(fd, &stat);
//the size of the file is now in stat.st_size
}
This avoids seeking to the beginning and end of the file.
See this article from JoelOnSoftware for why you don't want to use strcat.
Look at fread for an alternative. Use it with 1 for the size when you're reading bytes or characters.
Why don't you just use the array of chars you have? This ought to do it:
source[i] = getc(fp);
i++;
Not tested, but should work.. And yes, it could be better implemented with fread, I'll leave that as an exercise to the reader.
#define DEFAULT_SIZE 100
#define STEP_SIZE 100
char *buffer[DEFAULT_SIZE];
size_t buffer_sz=DEFAULT_SIZE;
size_t i=0;
while(!feof(fp)){
buffer[i]=fgetc(fp);
i++;
if(i>=buffer_sz){
buffer_sz+=STEP_SIZE;
void *tmp=buffer;
buffer=realloc(buffer,buffer_sz);
if(buffer==null){ free(tmp); exit(1);} //ensure we don't have a memory leak
}
}
buffer[i]=0;
Methinks you want fread:
http://www.cplusplus.com/reference/clibrary/cstdio/fread/
Have you considered mmap()? You can read from the file directly as if it were already in memory.
http://beej.us/guide/bgipc/output/html/multipage/mmap.html

Resources