views:

93

answers:

7

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?

+2  A: 

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

DVK
`read` will let you read in a certain number of characters. Read in enough to fill your buffer, then dump your buffer to the screen, clear it out, and repeat until you get to the end of the file.
bta
A: 

You can use fgets and limit the size of the read string.

char * fgets ( char * str, int num, FILE * stream );

At your code you can change the while to:

while(fgets(str, 100, file) != EOF) 
Edu
A: 

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.

RBerteig
A: 

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;
}
Ricardo
+1  A: 

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.

Alok
A: 

Completely depends on what you are trying to do- but did you consider using Perl, or any scripting language? Might make your job easier for text file processing!

A: 

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 doesnt set it so put a \0 in the last position
       //and buffer is now officialy a string
       buffer[string_size+1] = '\0';

       if (string_size != read_size) {
           //something went wrong, throw away the memory and set
           //the buffer to NULL
           free(buffer);
           buffer = NULL;
        }
    }

    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 :)

lfzawacki