Related
char* freadline(FILE* fp){
fseek(fp, 0, SEEK_END);
int lSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buffer = malloc(lSize);
fread(buffer, 1, lSize, fp);
fgets(buffer, sizeof(lSize), fp);
return buffer;
}
but it doesn't read line by line any suggestions as to how this would be read line by line
There are couple solutions here.
The first is to get the size of the entire file using fseek and ftell fseek will allow you to go to the end of file and ftell will give you the current position which can be used as a size indicator. You can then allocate enough of a buffer to read the entire file then split them up into lines.
The other solution is to use a temporary buffer of 1000 or so like you're already doing, read a character at a time using fgetc in a loop and feed it into the temporary buffer until you hit a new line indicator , then use the strlen method to get the length and allocate a buffer of that size, copy the temporary buffer then return the allocated buffer.
There is also errors in your code as pointed out in the comments. You're discarding your allocated memory resulting in a leak. And your freadline doesn't actually read a line it just reads whatever size you're telling it to read.
the lines in the file could be of any length.
realloc() is a classic approach, but how about a simple, slow and plodding one:
Read once to find line length, seek, allocate, then read again to save the line.
#include <stdio.h>
char* freadline(FILE *fp) {
int length = 0;
long offset = ftell(fp);
if (offset == -1)
return NULL;
int scan_count = fscanf(fp, "%*[^\n]%n", &length); // Save scan length
if (scan_count == EOF)
return NULL;
if (fseek(fp, offset, SEEK_SET))
return NULL;
size_t n = length + 1u; // +1 for potential \n
char *buf = malloc(n + 1); // + 1 for \0
if (buf == NULL)
return NULL;
size_t len = fread(buf, 1, n, fp);
buf[len] = '\0';
return buf;
}
Test
#include <assert.h>
#include <stdlib.h>
int main() {
FILE *fp = fopen("tmp.txt", "w+");
assert(fp);
for (int i = 0; i < 10; i++) {
int l = i * 7;
for (int j = 0; j < l; j++) {
fputc(rand() % 26 + 'a', fp);
}
fputc('\n', fp);
}
rewind(fp);
char *s;
while ((s = freadline(fp)) != NULL) {
printf("<%s>", s);
free(s);
}
fclose(fp);
return 0;
}
Output
<
><lvqdyoq
><ykfdbxnqdquhyd
><jaeebzqmtblcabwgmscrn
><oiaftlfpcuqffaxozqegxmwgglkh
><vxtdhnzqankyprbwteazdafeqxtijjtkwea
><zqgmplohyxrutojvbzllqgjaidbtqibygdzcxkujvw
><ghwbmjjmbpksnzkgzgiluiggpkzwhaetclrcyxcsixsutjmrm
><vqlybsjnihnfqyfhyszwgpsvnhnngdnjzjypqcflnztrhcfgbkakzxam
><alsuauxxchqjxqaiddtjszgcbullyyjymytioyawpzshhfpqpsatddbcagjgobm
>
If you're ok targeting POSIX, it already has a function that does what you need: getline.
#include <stdio.h>
#include <stdlib.h>
FILE *fh = ...;
char *line = NULL;
size_t buf_size = 0;
while (1) {
ssize_t line_len = getline(&line, &buf_size, fh);
if (line_len == -1)
break;
// ...
}
free(line);
If not, getline can be implemented using using fgets and realloc in a loop. Just start with a arbitrarily-sized buffer.
I'm trying to use LzmaLib's LzmaCompress() and LzmaDecompress() with buffers, adapting the examples provided here.
I'm testing with a ~3MB buffer and the compression function seems to work fine (produces a ~1.2MB compressed buffer), but when I try to decompress, it just extracts ~300 bytes and returns SZ_ERROR_DATA.
The few extracted bytes are right, but I don't know why it stops there.
My code:
#include <stdio.h>
#include <stdlib.h>
#include "LzmaLib.h"
void compress(
unsigned char **outBuf, size_t *dstLen,
unsigned char *inBuf, size_t srcLen)
{
unsigned propsSize = LZMA_PROPS_SIZE;
*dstLen = srcLen + srcLen / 3 + 128;
*outBuf = (unsigned char*)malloc(propsSize + *dstLen);
int res = LzmaCompress(
(unsigned char*)(*outBuf + LZMA_PROPS_SIZE), dstLen,
inBuf, srcLen,
*outBuf, &propsSize,
-1, 0, -1, -1, -1, -1, -1);
assert(res == SZ_OK);
*dstLen = *dstLen + LZMA_PROPS_SIZE;
}
void uncompress(
unsigned char **outBuf, size_t *dstLen,
unsigned char *inBuf, size_t srcLen
) {
*dstLen = 5000000;
*outBuf = (unsigned char*)malloc(*dstLen);
srcLen = srcLen - LZMA_PROPS_SIZE;
int res = LzmaUncompress(
*outBuf, dstLen,
(unsigned char*)(inBuf + LZMA_PROPS_SIZE), &srcLen,
inBuf, LZMA_PROPS_SIZE);
assert(res == SZ_OK);
}
void do_compress() {
FILE* file = fopen("Module.dll", "r");
size_t size, decSize;
unsigned char *data, *dec = NULL;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
fread(data, 1, size, file);
fclose(file);
compress((unsigned char**)&dec, &decSize, data, size);
file = fopen("Module.lzma", "w");
fwrite(dec, 1, decSize, file);
fclose(file);
}
void do_uncompress() {
FILE* file = fopen("Module.lzma", "r");
size_t size, decSize;
unsigned char *data, *dec = NULL;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, 0L, SEEK_SET);
data = (unsigned char*)malloc(size);
fread(data, 1, size, file);
fclose(file);
uncompress((unsigned char**)&dec, &decSize, data, size);
file = fopen("Module_DEC.dll", "w");
fwrite(dec, 1, decSize, file);
fclose(file);
}
int main()
{
do_compress();
do_uncompress();
return 0;
}
If this code is not the better way to compress buffers with LzmaLib, I'm happy to accept suggestions.
I bet the problem lurks in how you read/write your files. You need to open them in binary mode to prevent any substitutions during read/write operations.
Change all instances of:
fopen(xxx, "r") -> fopen(xxx, "rb")
fopen(xxx, "w") -> fopen(xxx, "wb")
I didn't check this specificly for LzmaCompress but most of the other compressing libraries like libz handle that function similar to the standard read/write or fread/fwrite functions, i.e. allowing you to continuously calling the functions to compress more and more data in one stream. So at some point, you will have to say "I'm done, please flush everything not written so far". Possibly, you forgot that part. If not, a Minimal, Complete, and Verifiable example would be cool.
When you compress, you pass the number of compressed output bytes to the caller. But your buffer contains LZMA_PROPS_SIZE additional bytes. So, when writing the lzma file, you actually forget the last LZMA_PROPS_SIZE bytes and on later reading, those are missing.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *f;
f = fopen("my file.txt", "w");
int n = 5;
fprintf(f, "n equals to %d", n);
fclose(f);
f = fopen("my file2.txt", "w");
char *txt = "New file";
fwrite(txt, 1, strlen(txt), f);
fclose(f);
f = fopen("my file3.txt", "w");
char *txt2 = "Hello";
for(int i = 0; i < strlen(txt2); i++)
{
printf("Mouse cursor at %d.\n", ftell(f));
fputc(txt2[i], f);
}
fclose(f);
f = fopen(__FILE__, "r");
char str[1024];
while (!feof(f))
{
fscanf(f, "%s", str);
puts(str);
}
putchar('\n');
fclose(f);
f = fopen(__FILE__, "r");
long size = fseek(f, 0, SEEK_END);
char *buffer = malloc(sizeof(char) * size + 1);
fread(buffer, 1, size, f);
puts(buffer);
free(buffer);
fclose(f);
return 0;
}
Take a look in this part of the code :
f = fopen(__FILE__, "r");
long size = fseek(f, 0, SEEK_END);
char *buffer = malloc(sizeof(char) * size + 1);
fread(buffer, 1, size, f);
puts(buffer);
free(buffer);
fclose(f);
I've tried to print the code in my file and this is what I wrote to do it ^
When I try to print it with puts function it prints 3 characters :
http://i61.tinypic.com/ortdvl.png
The third character is changing in each execution.
Anyway to the question, I don't know why this happens can someone explain me what I did wrong ?
fseek(f, 0, SEEK_END);
long size = ftell(f);
char *buffer = calloc(size + 1, sizeof(char));
rewind(f);
fread(buffer, 1, size, f);
I am reading a text file and trying to display its contents on the console. Here is my code:
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <fstream>
int main()
{
FILE* fp=NULL;
char buff[100];
fp=fopen("myfile.txt","r");
if(fp==NULL)
{
printf("Couldn't Open the File!!!\n");
}
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
fread(buff,file_size,1,fp);
printf("Data Read [%s]",buff);
fclose(fp);
return 0;
}
but only redundant data is being displayed on the console; could someone please point out my mistake?
You forgot to reset the file pointer to start after doing this.
fseek(fp, 0, SEEK_END);
Do this after finding size (file_size).
rewind (fp);
You need to seek back to the start of the file before reading:
int main()
{
FILE* fp=NULL;
char buff[100];
fp=fopen("myfile.txt","r");
if(fp==NULL)
{
printf("Couldn't Open the File!!!\n");
exit(1); // <<< handle fopen failure
}
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
fseek(fp, 0, SEEK_SET); // <<< seek to start of file
fread(buff,file_size,1,fp);
printf("Data Read [%s]",buff);
fclose(fp);
return 0;
}
Try it....
#include <stdio.h>
#include <stdlib.h>
void handle_line(char *line) {
printf("%s", line);
}
int main(int argc, char *argv[]) {
int size = 1024, pos;
int c;
char *buffer = (char *)malloc(size);
FILE *f = fopen("myfile.txt", "r");
if(f) {
do { // read all lines in file
pos = 0;
do{ // read one line
c = fgetc(f);
if(c != EOF) buffer[pos++] = (char)c;
if(pos >= size - 1) { // increase buffer length - leave room for 0
size *=2;
buffer = (char*)realloc(buffer, size);
}
}while(c != EOF && c != '\n');
buffer[pos] = 0;
// line is now in buffer
handle_line(buffer);
} while(c != EOF);
fclose(f);
}
free(buffer);
return 0;
}
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <fstream>
int main()
{
FILE* fp=NULL;
char *buff; //change array to pointer
fp=fopen("myfile.txt","r");
if(fp==NULL)
{
printf("Couldn't Open the File!!!\n");
}
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
buff = malloc(file_size); //allocating memory needed for reading file data
fseek(fp,0,SEEK_SET); //changing fp to point start of file data
fread(buff,file_size,1,fp);
printf("Data Read [%s]",buff);
fclose(fp);
return 0;
}
having a buffer of 100 bytes to read a file is not a better idea as since the file size may be more than 100 bytes.
A better file io can be done by doing a fgets on the file, if its not a type of metadata that you wanted to read using the fread.
fgets in a while loop can be used to check whether its reached EOF or a feof call can be used to check the EOF.
a sample code listing of fgets can be like this:
while (fgets(buf, len, fp)) {
printf("%s", buf);
}
or a sample that is used with fgets can be like this:
while (fread(buf, len, 1, fp) >= 0) {
printf("%s\n", buf);
}
What is the simplest way (least error-prone, least lines of code, however you want to interpret it) to open a file in C and read its contents into a string (char*, char[], whatever)?
I tend to just load the entire buffer as a raw memory chunk into memory and do the parsing on my own. That way I have best control over what the standard lib does on multiple platforms.
This is a stub I use for this. you may also want to check the error-codes for fseek, ftell and fread. (omitted for clarity).
char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
// start to process your data / extract strings here...
}
Another, unfortunately highly OS-dependent, solution is memory mapping the file. The benefits generally include performance of the read, and reduced memory use as the applications view and operating systems file cache can actually share the physical memory.
POSIX code would look like this:
int fd = open("filename", O_RDONLY);
int len = lseek(fd, 0, SEEK_END);
void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
Windows on the other hand is little more tricky, and unfortunately I don't have a compiler in front of me to test, but the functionality is provided by CreateFileMapping() and MapViewOfFile().
If "read its contents into a string" means that the file does not contain characters with code 0, you can also use getdelim() function, that either accepts a block of memory and reallocates it if necessary, or just allocates the entire buffer for you, and reads the file into it until it encounters a specified delimiter or end of file. Just pass '\0' as the delimiter to read the entire file.
This function is available in the GNU C Library, http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994
The sample code might look as simple as
char* buffer = NULL;
size_t len;
ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp);
if ( bytes_read != -1) {
/* Success, now the entire file is in the buffer */
If you are reading special files like stdin or a pipe, you are not going to be able to use fstat to get the file size beforehand. Also, if you are reading a binary file fgets is going to lose the string size information because of embedded '\0' characters. Best way to read a file then is to use read and realloc:
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main () {
char buf[4096];
ssize_t n;
char *str = NULL;
size_t len = 0;
while (n = read(STDIN_FILENO, buf, sizeof buf)) {
if (n < 0) {
if (errno == EAGAIN)
continue;
perror("read");
break;
}
str = realloc(str, len + n + 1);
memcpy(str + len, buf, n);
len += n;
str[len] = '\0';
}
printf("%.*s\n", len, str);
return 0;
}
Note: This is a modification of the accepted answer above.
Here's a way to do it, complete with error checking.
I've added a size checker to quit when file was bigger than 1 GiB. I did this because the program puts the whole file into a string which may use too much ram and crash a computer. However, if you don't care about that you could just remove it from the code.
#include <stdio.h>
#include <stdlib.h>
#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TOO_LARGE 2
#define FILE_READ_ERROR 3
char * c_read_file(const char * f_name, int * err, size_t * f_size) {
char * buffer;
size_t length;
FILE * f = fopen(f_name, "rb");
size_t read_length;
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
// 1 GiB; best not to load a whole large file in one string
if (length > 1073741824) {
*err = FILE_TOO_LARGE;
return NULL;
}
buffer = (char *)malloc(length + 1);
if (length) {
read_length = fread(buffer, 1, length, f);
if (length != read_length) {
free(buffer);
*err = FILE_READ_ERROR;
return NULL;
}
}
fclose(f);
*err = FILE_OK;
buffer[length] = '\0';
*f_size = length;
}
else {
*err = FILE_NOT_EXIST;
return NULL;
}
return buffer;
}
And to check for errors:
int err;
size_t f_size;
char * f_data;
f_data = c_read_file("test.txt", &err, &f_size);
if (err) {
// process error
}
else {
// process data
free(f_data);
}
What is the simplest way (least error-prone, least lines of code, however you want to interpret it) to open a file in C and read its contents into a string ...?
Sadly, even after years, answers are error prone and many lack proper string formation and error checking.
#include <stdio.h>
#include <stdlib.h>
// Read the file into allocated memory.
// Return NULL on error.
char* readfile(FILE *f) {
// f invalid? fseek() fail?
if (f == NULL || fseek(f, 0, SEEK_END)) {
return NULL;
}
long length = ftell(f);
rewind(f);
// Did ftell() fail? Is the length too long?
if (length == -1 || (unsigned long) length >= SIZE_MAX) {
return NULL;
}
// Convert from long to size_t
size_t ulength = (size_t) length;
char *buffer = malloc(ulength + 1);
// Allocation failed? Read incomplete?
if (buffer == NULL || fread(buffer, 1, ulength, f) != ulength) {
free(buffer);
return NULL;
}
buffer[ulength] = '\0'; // Now buffer points to a string
return buffer;
}
Note that if the text file contains null characters, the allocated data will contain all the file data, yet the string will appear to be short. Better code would also return the length information so the caller can handle that.
char* readfile(FILE *f, size_t *ulength_ptr) {
...
if (ulength_ptr) *ulength_ptr == *ulength;
...
}
If the file is text, and you want to get the text line by line, the easiest way is to use fgets().
char buffer[100];
FILE *fp = fopen("filename", "r"); // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
If you're using glib, then you can use g_file_get_contents;
gchar *contents;
GError *err = NULL;
g_file_get_contents ("foo.txt", &contents, NULL, &err);
g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
if (err != NULL)
{
// Report error to user, and free error
g_assert (contents == NULL);
fprintf (stderr, "Unable to read file: %s\n", err->message);
g_error_free (err);
}
else
{
// Use file contents
g_assert (contents != NULL);
}
}
Just modified from the accepted answer above.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *readFile(char *filename) {
FILE *f = fopen(filename, "rt");
assert(f);
fseek(f, 0, SEEK_END);
long length = ftell(f);
fseek(f, 0, SEEK_SET);
char *buffer = (char *) malloc(length + 1);
buffer[length] = '\0';
fread(buffer, 1, length, f);
fclose(f);
return buffer;
}
int main() {
char *content = readFile("../hello.txt");
printf("%s", content);
}
// Assumes the file exists and will seg. fault otherwise.
const GLchar *load_shader_source(char *filename) {
FILE *file = fopen(filename, "r"); // open
fseek(file, 0L, SEEK_END); // find the end
size_t size = ftell(file); // get the size in bytes
GLchar *shaderSource = calloc(1, size); // allocate enough bytes
rewind(file); // go back to file beginning
fread(shaderSource, size, sizeof(char), file); // read each char into ourblock
fclose(file); // close the stream
return shaderSource;
}
This is a pretty crude solution because nothing is checked against null.
I will add my own version, based on the answers here, just for reference. My code takes into consideration sizeof(char) and adds a few comments to it.
// Open the file in read mode.
FILE *file = fopen(file_name, "r");
// Check if there was an error.
if (file == NULL) {
fprintf(stderr, "Error: Can't open file '%s'.", file_name);
exit(EXIT_FAILURE);
}
// Get the file length
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
// Create the string for the file contents.
char *buffer = malloc(sizeof(char) * (length + 1));
buffer[length] = '\0';
// Set the contents of the string.
fread(buffer, sizeof(char), length, file);
// Close the file.
fclose(file);
// Do something with the data.
// ...
// Free the allocated string space.
free(buffer);
easy and neat(assuming contents in the file are less than 10000):
void read_whole_file(char fileName[1000], char buffer[10000])
{
FILE * file = fopen(fileName, "r");
if(file == NULL)
{
puts("File not found");
exit(1);
}
char c;
int idx=0;
while (fscanf(file , "%c" ,&c) == 1)
{
buffer[idx] = c;
idx++;
}
buffer[idx] = 0;
}