I am trying to read a RSA key file into a buffer with the code below
char* readkeyBuffer(){
char *buffer;
long length;
FILE *f;
f= fopen ("file.p12", "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
rewind(f);
//fseek (f, 0, SEEK_SET);
buffer = (char *) malloc (sizeof(char) * (length +1 ));
lr_message("Length = %d",length);
lr_message("sizeof Buffer = %d",sizeof(buffer));
if (buffer)
{
fread (buffer, 1, length, f);
//strcat(buffer,'\0');
}
lr_message("sizeof Buffer = %d",sizeof(buffer));
lr_message("buffer len = %d",strlen(buffer));
//lr_message("%s",buffer);
fclose (f);
}
return buffer;
}
The file size is 4476 , but somehow the file being read into the buffer has only 59 chars. Can you please suggest what is the issue?
Output ---
Length = 4476
sizeof Buffer = 4
sizeof Buffer = 4
buffer len = 59
While reading a file into char *, where should the null be added and why? Option1 or option2, both seem to compile.
char* load_file(char const* path)
{
char* buffer = 0;
long length;
FILE * f = fopen (path, "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = (char*)malloc ((length+1)*sizeof(char));
if (buffer)
{
fread (buffer, sizeof(char), length, f);
}
fclose (f);
}
buffer[length] = '\0'; //option1
buffer[length+1] = '\0'; //Option2
return buffer;
}
With your malloc call you allocate an "array" of length + 1 characters, with indexes from 0 to length (inclusive). Therefore the correct option can only be "option1".
#EDIT
Looks like fread function reads more characters than record_size parameter ;x
PICTURE
I've got 2 functions which sort file(bubble sort) by records(key is first character). The first one is using system functions(read, write, etc.) and secong is using library functions(fread, fwrite, etc.). For small record_size parameter both works well but e.g for record_size = 5000 only sys_sort works properly. File sorted by lib_sort has less lines and different lengths. Why? I don't know what is the problem.
void lib_sort(const char *filename, long long int record_size, long long int num_of_lines) {
record_size++; // '\n' char at the end of line
FILE *file;
if (!(file = fopen(filename, "r+"))) {
printf("Cannot open %s file.\n", filename);
fclose(file);
exit(EXIT_FAILURE);
}
char *buffer1 = malloc(sizeof(char) * record_size);
char *buffer2 = malloc(sizeof(char) * record_size);
bool flag = true;
while (flag) {
flag = false;
if(fseek(file, 0, SEEK_SET) != 0) {
printf("fseek failed.\n");
}
if((fread(buffer1, sizeof(char), (size_t) record_size, file)) != record_size) {
printf("fread failed.\n");
}
for (int i = 1; i < num_of_lines; ++i) {
if((fread(buffer2, sizeof(char), (size_t) record_size, file)) != record_size) {
printf("fread failed.\n");
}
if (buffer1[0] > buffer2[0]) {
if(fseek(file, record_size * (-2), SEEK_CUR) != 0) {
printf("fseek failed.\n");
}
if((fwrite(buffer2, sizeof(char), (size_t) record_size, file)) != record_size) {
printf("fwrite failed.\n");
}
if((fwrite(buffer1, sizeof(char), (size_t) record_size, file)) != record_size) {
printf("write failed.\n");
}
flag = true;
} else {
char *tmp = buffer2;
buffer2 = buffer1;
buffer1 = tmp;
}
}
num_of_lines--;
}
fclose(file);
free(buffer1);
free(buffer2);
}
And this is the correct one:
void sys_sort(const char *filename, long long int record_size, long long int num_of_records) {
record_size++; // '\n' char at the end of line
int file;
if ((file = open(filename, O_RDWR)) < 0) {
printf("Cannot open %s file.\n", filename);
close(file);
exit(EXIT_FAILURE);
}
char *buffer1 = malloc(sizeof(char) * record_size);
char *buffer2 = malloc(sizeof(char) * record_size);
bool flag = true;
while (flag) {
flag = false;
lseek(file, 0, SEEK_SET);
read(file, buffer1, (size_t) record_size);
for (int i = 1; i < num_of_records; ++i) {
read(file, buffer2, (size_t) record_size);
if (buffer1[0] > buffer2[0]) {
lseek(file, record_size * (-2), SEEK_CUR);
write(file, buffer2, (size_t) record_size);
write(file, buffer1, (size_t) record_size);
flag = true;
} else {
char *tmp = buffer2;
buffer2 = buffer1;
buffer1 = tmp;
}
}
num_of_records--;
}
close(file);
free(buffer1);
free(buffer2);
}
I use ubuntu 16.04 and standard C99
You are using fread() and fwrite() incorrectly.
size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream );
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
Description
The function fread() reads nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.
You are telling fread() and fwrite() that the length of your record or item is 1 byte long and you are asking for 5000 records.
Return Value
On success, fread() and fwrite() return the number of items read or written. This number equals the number of bytes transferred only when size is 1. If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).
Thee parameters you pass to fread() and fwrites() are in the wrong order when in your code you clearly meant the record size (length of the item) is record_size or 5000 in your failing scenario.
You should have written your code to call fread() in this manner instead:
fread(buffer1, (size_t) record_size, 1, file)
and call fwrite() in this manner:
fwrite(buffer2, (size_t) record_size, 1, file)
It should also be noted that fread() and fwrite() works on binary streams. This means that strings are not automatically null terminated and reading will read past newlines and past null \0 bytes. On writes, newlines are not automatically converted to OS supported newlines such as LF on Linux and CRLF on Windows.
For string operations, use fgets() and fputs() instead.
You have forgotten to mention and I have wrongly assumed that you are running on Linux. Based on your comment, you are running on Windows after all. On Windows, fread() and fwrite() will not work correctly when the file is opened in text mode due to translations with OS dependent encoding. You will need to open the file in binary mode.
I put fseek(file, 0, SEEK_CUR); after every fread() and fwrite() functions and that worked for me. I don't know why.
I have a file that I need to read into a buffer (char *) but the problem is that the file has some "funny characters" in it inbetween the valid text.
So when I write some code like the following:
FILE *fp;
if((fp = fopen(".\\test.txt", "rt"))==NULL){
printf("Cannot open file2\n");
}
fseek(fp, 0, SEEK_END);
long int fsize = ftell(fp);
rewind(fp);
//char *buffer2 = malloc(fsize * sizeof(char));
buffer = malloc(fsize * sizeof(char));
fread(buffer, 1, fsize, fp);
buffer[fsize] = '\0';
fclose(fp);
printf("fsize = %i\n", fsize);
printf("Buffer = %s\n", buffer);
It only prints out the first part of the text file like follows:
Buffer = header
And obviously stops at the first NUL char.
Is thier any way to read the entire buffer of the file, including funny chars?
Or is this not possible in C?
The FSIZE is read correctly, just the FREAD does not read the entire buffer ;-(
Any help would be greatly appreciated ;-)
Thanks
Lynton
UPDATE: OK, I was being a little stupid.....if I write the buffer to a file it has everything in it, only if I write it out to the screen does it stop at the null so that is fine.
Don't open the file in "text" mode ("rt"), use binary mode instead ("rb").
Also, it might well be reading the data, but the printf("Buffer = %s\n", buffer) will only print up to the first NUL, so your debug is not going to do what your want. You probably want to write a little hex dumping function.
How to read all contents of file, including NUL chars between valid text?
Errors:
Allocate enough space if attempting to make a string. OP's code is 1 short. This is a dubious goal if data read may include null chracters.
Open in binary mode #Lawrence Dol
Some more error checking is useful.
// FILE *fp = fopen(".\\test.txt", "rt");
FILE *fp = fopen(".\\test.txt", "rb");
if (fp==NULL) {
printf("Cannot open file2\n");
exit(-1);
}
if (fseek(fp, 0, SEEK_END)) {
printf("fseek() trouble\n");
exit(-1);
}
long fsize = ftell(fp);
if (fsize == -1 || fsize >= SIZE_MAX) {
printf("fell() trouble\n");
exit(-1);
}
// Add 1 if trying to make a string.
size_t sz = (size_t) fsize;
if (making_a_string) sz++;
rewind(fp);
char *buffer = malloc(sizeof *buffer * sz);
if (buffer == NULL && sz > 0) { // Tolerate a file size of 0
printf("malloc() trouble\n");
exit(-1);
}
size_t in = fread(buffer, 1, fsize, fp);
fclose(fp);
if (in != fsize) {
printf("fread() trouble\n");
exit(-1);
}
if (making_a_string) {
buffer[fsize] = '\0';
}
To print the entire data, use, fwrite(). In order to print a character array, a trailing null chracter is not needed as in a string, but the length of the character array is used.
printf("fsize = %ld\n", fsize); // Note: %ld
printf("Buffer = <", );
fwrite(buffer, 1, fsize, stdout);
printf(">\n");
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;
}