I am writing a program in C. I use low level functions like open, read, close. I have a file descriptor, etc, but I don't know how to print only the first 2 lines from a file that has e.g. 30 lines of text. how to do it?
you need to read a file into a string, iterate through the string, concat any character into the string variable, define a int variable for lines count, when lines reaches 2, break the loop
here’s an example how you can do it
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_first_two_lines(char *file_name) {
FILE *file = fopen(file_name, "r");
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
char *buffer = malloc(size);
fread(buffer, 1, size, file);
char *two_lines = calloc(1, sizeof(char));
unsigned int lines = 0;
for (int i=0;i<strlen(buffer);i++) {
if (lines == 2) break;
if (buffer[i] == '\n') {
if (lines < 1) {
two_lines = realloc(two_lines, (strlen(two_lines) + 2) * sizeof(char));
strcat(two_lines, (char []) {'\n', 0});
}
lines++;
continue;
}
two_lines = realloc(two_lines, (strlen(two_lines) + 2) * sizeof(char));
strcat(two_lines, (char []) {buffer[i], 0});
}
return two_lines;
}
int main(int argc, char *argv[]) {
char *first_two_lines = get_first_two_lines("file_name");
printf("%s", first_two_lines);
return 0;
}
Related
When I write my string to file, I first write the length of the string as an int, followed by the string itself. Here is my code:
int wordLength = strlen(words);
fwrite(&wordLength,sizeof(int),1, outputFile);
fwrite(&words,sizeof(char),strlen(words), outputFile);
However, when I fread it back, I get an empty string. Here is my reading code:
int strLength;
fread(&strLength, sizeof(int), 1, f);
char* word = (char*) malloc(strLength*sizeof(char));
fread(&word, sizeof(char), strLength, f);
Why is this happening?
when I fread it back, I get an empty string. Here is my reading code:
Why is this happening?
fread(&strLength, sizeof(int), 1, f);
char* word = (char*) malloc(strLength*sizeof(char));
fread(&word, sizeof(char), strLength, f);
Code allocates insufficient memory. strLength*sizeof(char) is enough for the text yet not the terminating null character to make a string.
// char* word = (char*) malloc(strLength*sizeof(char));
char* word = malloc(strLength + 1u); // add 1
fread(&word, ...); is attempting to read data into the address of word, rather than into the memory just allocated.
// fread(&word, sizeof(char), strLength, f);
fread(word, sizeof *word, strLength, f); // drop &
The null character is never appended.
size_t count = fread(word, sizeof *word, strLength, f);
if (count != strLength) puts("Error");
else {
word[strLength] = '\0';
puts(word);
}
Notes:
Better to use size_t wordLength
Checking the return value of malloc() makes for good code.
size_t wordLength = strlen(words);
...
char* word = malloc(strLength + 1);
if (word == NULL) Hanlde_OutOfMemory();
Post does not show file open/closing details. Code may need to rewind(f) before reading data written.
This works on Ubuntu:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *outputFile;
FILE *inputFile;
char words[] = "This is a series of words";
int wordLength = strlen(words);
outputFile = fopen("outputFile", "w");
if ( outputFile == NULL )
{
perror("fopen failed: ");
exit(1);
}
fwrite(&wordLength,sizeof(int),1, outputFile);
fwrite(words,sizeof(char),strlen(words), outputFile);
fclose(outputFile);
inputFile = fopen("outputFile", "r");
if ( inputFile == NULL )
{
perror("fopen(2) failed: ");
exit(1);
}
int strLength = -99;
fread(&strLength, sizeof(int), 1, inputFile);
char* buff = (char*) malloc(strLength*sizeof(char));
fread(buff, sizeof(char), strLength, inputFile);
buff[strLength] = 0x00;
printf("Input Str: -->%s<--\n", buff);
}
I read a file and stock all characters like this:
void ReadFile()
{
int c;
FILE *file;
int string_size;
file = fopen("/userFiles/ex.txt", "r");
char * content;
if (file)
{
// Seek the last byte of the file
fseek(file, 0, SEEK_END);
// Offset from the first to the last byte, or in other words, filesize
string_size = ftell(file);
// go back to the start of the file
rewind(file);
// Allocate a string that can hold it all
content = malloc((string_size + 1) * sizeof(char));
int i = 0;
while ((c = getc(file)) != EOF)
{
//printf("%c",(char) c);
content[i] = (char) c;
i++;
}
content[string_size] = '\0';
printf("content: %s",content);
fclose(file);
}
else
{
printf("not load\n");
}
}
Problem is if i read each carachter i've got the content of the file but if i do:
printf("content: %s",content);
I got just a symbol and not text whereas i need to pass the content var with correct text in argument of a json reply.
This is the first line of the file (CRC32):
�ex.txt k��X� ?xml version="1.0" encoding="utf-8"?
I compiled and ran the following code and it shows no major problem when executed.
The compilable version I used is (cmdline: gcc main.c -Wall -Wextra -o main):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int c;
FILE *file;
int string_size;
file = fopen("plop", "r");
char * content;
if (file == NULL)
{
perror("fprintf");
return 1;
}
// Seek the last byte of the file
fseek(file, 0, SEEK_END);
// Offset from the first to the last byte, or in other words, filesize
string_size = ftell(file);
// go back to the start of the file
rewind(file);
// Allocate a string that can hold it all
content = malloc((string_size + 1) * sizeof(char));
int i = 0;
while ((c = getc(file)) != EOF)
{
//printf("%c",(char) c);
content[i] = (char) c;
i++;
}
content[string_size] = '\0';
printf("content: %s", content);
return 0;
}
Maybe your file has a binary content?
What is the symbol printed, that you mentioned?
I think you should use quotes "" around the content string:
printf("content: \"%s\"",content);
I am reading a string from a file. After like the second or third time the function gets executed, one or more random characters become appended to the buffer string and I have no idea why that happens.
Here's the piece of code:
scorefile = fopen("highscore.dat", "rb");
if (scorefile)
{
fseek(scorefile, 0, SEEK_END);
length = ftell(scorefile);
fseek(scorefile, 0, SEEK_SET);
buffer = malloc(length);
if (buffer)
{
fread(buffer, 1, length, scorefile);
}
fclose(scorefile);
}
Am I doing something wrong here?
Let's spell it all out and go slightly more robust:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char *loadScoreFile(const char *filename)
{
char *buffer = NULL;
FILE *scorefile = fopen(filename, "r");
if (scorefile != NULL)
{
(void) fseek(scorefile, 0, SEEK_END);
int length = ftell(scorefile);
(void) fseek(scorefile, 0, SEEK_SET);
buffer = malloc(length + 1);
if (buffer != NULL)
{
assert(length == fread(buffer, 1, length, scorefile));
buffer[length] = '\0';
}
(void) fclose(scorefile);
}
return buffer;
}
int main()
{
for (int i = 0; i < 10; i++)
{
char *pointer = loadScoreFile("highscore.dat");
if (pointer != NULL)
{
printf("%s", pointer);
free(pointer);
}
}
return 0;
}
if you use buffer = malloc(length);, and then read length bytes into it, it will be one byte too short. Char arrays in C are zero-terminated, so they need an extra byte to but that zero. buffer = malloc(length+1); will fix this.
#include <stdio.h>
#include <stdlib.h>
int count_arr(FILE *file)
{
int c,count=0;
//FILE *file;
//file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF){
putchar(c);
++count;}
fclose(file);
}
return count;
}
void make_arr (FILE *file, char arr[]){
int c,n=0,count=0;
char ch;
//FILE *file;
//file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF){
ch = (char)c;
arr[n]=ch;
++n; }
fclose(file);
}
}
int main(){
FILE *file;
int n;
//scanf("%c",&file_name);
file = fopen("test.txt","r");
int count = count_arr(file);
char arr [count];
make_arr(file, arr);
for(n=0; n<count;++n) printf("%c",arr[n]);
}
So far this is all I have for my code. I know I am doing it completely wrong. When I print out the char array it prints random junk... I am trying to code a function "make_arr" that passes an array which gets stored with characters from a file. Any help would be appreciated!
Here is an small example that reads a file into a buffer:
FILE* file = fopen("file.txt", "r");
// get filesize
fseek(file, 0, SEEK_END);
int fsize = ftell(file);
fseek(file, 0, SEEK_SET);
// allocate buffer **note** that if you like
// to use the buffer as a c-string then you must also
// allocate space for the terminating null character
char* buffer = malloc(fsize);
// read the file into buffer
fread(buffer, fsize, 1, file);
// close the file
fclose(file);
// output data here
for(int i = 0; i < fsize; i++) {
printf("%c", buffer[i]);
}
// free your buffer
free(buffer);
If you really would like to use a function to fill your buffer this would work (not really see the point though), although I still will make only one read operation:
void make_array(FILE* file, char* array, int size) {
// read entire file into array
fread(array, size, 1, file);
}
int main(int argc,char** argv) {
// open file and get file size by first
// moving the filepointer to the end of the file
// and then using ftell() to tell its position ie the filesize
// then move the filepointer back to the beginning of the file
FILE* file = fopen("test.txt", "r");
fseek(file, 0, SEEK_END);
int fs = ftell(file);
fseek(file, 0, SEEK_SET);
char array[fs];
// fill array with content from file
make_array(file, array, fs);
// close file handle
fclose(file);
// output contents of array
for(int i = 0; i < fs; i++) {
printf("%c\n", array[i]);
}
return 0;
}
Like I stated in the comments above you need to add space for the terminating null character if you like to use the char array as a string:
char* array = malloc(fs + 1);
fread(array, fs, 1, file);
// add terminating null character
array[fs] = '\0';
// print the string
printf("%s\n", array);
How can I traverse a file line by line going from the bottom up? For example, here is my code for traversing it from top to bottom:
void *readFileTB(char *str1)
{
int size = 1024;
char *buffer = malloc(size);
FILE *fp;
fp = fopen("testfile.txt", "r");
while(fgets(buffer, 1024, fp)) //get a line from a file
{
printf(buffer);
}
return 0;
}
If a file contains:
line1onetest
line2twotest
line3threetest
This function will print the following if executed:
line1onetest
line2twotest
line3threetest
How can I write a function that does the above but in the opposite direction so it outputs the following?
line3threetest
line2twotest
line1onetest
Any thoughts?
Line by line it's a little difficult. If we start with bytes, it's pretty simply: we first fseek to a little before the bottom:
if(fseek(fp, 256, SEEK_END) == -1) { /* handle error */ }
Since we've seeked 256 bytes before the end, we can read 256 bytes. Then we can seek back 256 more bytes, etc., until we hit the top of the file.
Now if you're trying to read lines of text, this can be tricky: you need to read a number of bytes at the end of the file and find the last newline character. If there is none, you didn't read enough and you need to read more. Once you've found it, your line starts there. To read the next line, you need to seek backwards again and don't go past your previous line start.
Here, I got a bit into it and coded the entire thing. I have no clue if it's any good, but at least you can get an idea of how it works. (I have a feeling there are better ways to do this)
To compile and use program:
$ gcc -Wall -o reverser main.c
Usage:
$ ./reverser text.txt
text.txt contents:
int main(int argc, char *argv[]){
if(argc != 2)
return 1;
print_rev_file(argv[1], 64);
return 0;
}
Results:
}
return 0;
print_rev_file(argv[1]);
return 1;
if(argc != 2)
int main(int argc, char *argv[]){
How to use in code:
main.c
#include <header.h>
int main(int argc, char *argv[]){
if(argc != 2)
return 1;
print_rev_file(argv[1], 64);
return 0;
}
header.h:
Note: It's bad form to use double underscore because many compilers use them.
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
///SUPPORT for get_line
size_t __file_size(FILE ** file); //It'd make sense to homogenize the parameters...
char * __get_line_copy(FILE ** file, size_t chunk_size, size_t position);
char * __get_line(int line_number, FILE ** file, size_t chunk_size);
size_t __nth_line(FILE ** file, int line_number, size_t chunk_size);
unsigned int __line_count(FILE ** file, size_t chunk_size);
#define file_size(x) __file_size(&x)
size_t __file_size(FILE ** file){
size_t old_pos = ftell(*file);
fseek(*file, 0, SEEK_END);
int file_size = ftell(*file);
fseek(*file, 0, old_pos);
return file_size;
}
char * __get_line_copy(FILE ** file, size_t chunk_size, size_t position){
int i;
char c;
char * buffer = malloc(chunk_size);
memset(buffer, 0, chunk_size);
size_t old_pos = ftell(*file);
fseek(*file, position, SEEK_SET);
for(i = 0; (i < chunk_size && (c = fgetc(*file)) != '\n' && !feof(*file)); i++){
*(buffer+i) = c;
}
*(buffer+chunk_size) = '\0';
fseek(*file, 0, old_pos);
return buffer;
}
#define FIRST 0
#define LAST -1
#define get_line(x, y, z) __get_line(x, &y, z);
char * __get_line(int line_number, FILE ** file, size_t chunk_size){
char * line = __get_line_copy(file, chunk_size, __nth_line(file, line_number, chunk_size));
return line;
}
size_t __nth_line(FILE ** file, int line_number, size_t chunk_size){
int i = 0, index;
size_t old_pos = ftell(*file);
fseek(*file, 0, SEEK_SET);
if(line_number > 0){
while(i <= line_number && !feof(*file)){
if(fgetc(*file) == '\n')
i++;
}
} else {
while(!feof(*file)){
if(fgetc(*file) == '\n')
i++;
}
index = i + (line_number+1);
fseek(*file, 0, SEEK_SET);
int i = 0;
while(i < index){
if(fgetc(*file) == '\n')
i++;
}
}
size_t position = ftell(*file);
fseek(*file, 0, old_pos);
return position;
}
#define line_count(x, y) __line_count(&x, y)
unsigned int __line_count(FILE ** file, size_t chunk_size){
int i = 1;
while(!feof(*file))
if(fgetc(*file) == '\n')
i++;
return i;
}
int print_rev_file(char * filename, size_t buffer){
FILE * file = fopen(filename, "r");
if(file == NULL){
return -1;
}
int i, lines = line_count(file, buffer);
for(i = 0; i < lines; i++){
char * line = get_line(LAST-i, file, buffer);
puts(line);
free(line);
}
return 0;
}
int main(int argc, char *argv[]){
if(argc != 2)
return 1;
print_rev_file(argv[1], 64);
return 0;
}
There's a utility in the GNU coreutils called tac that does exactly that.
You can view the source for it below.
http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob_plain;f=src/tac.c;hb=HEAD