fseek From one line to Another - c

I want to read into a buffer a couple of lines from a file.txt.
At the moment I fseek and fread every line in a loop. I know what the lines are because I keep a list of their indices. So if I want to read from line 5 to line 10, I know exactly what those lines are in the file.txt. I never have to read the whole file.
I want to do something like this:
char buffer[2000];
FP *fp;
fseek(fp, start_index, end_index, SEEK_SET);
fgets(buffer, 2000, fp);
How do I do something like that? fseek doesn't take that many parameters.
Textfile looks like this
apple: a fruit.
apple pie: a pie made from apples.

If I understood you right, all you'll have to do is calculating the length of your section and read that rather than up to 2000 characters:
fseek(fp, start_index, SEEK_SET);
fread(buffer, sizeof(char), end_index - start_index, fp);
Of course, keep in mind that I didn't include any length/error checking and no null terminator for the buffer etc. You could allocate the buffer dynamically to fix that:
long len = end_index - start_index;
char *buffer = new buffer[len + 1];
fseek(fp, start_index, SEEK_SET);
fread(buffer, sizeof(char), len, fp);
buffer[len] = 0;

you can do it like this.
char buffer[5][1024];//save 5 lines.If a line to a maximum of 1024 characters
char buff_line[1024];//for fgets buff
FILE *fp = NULL;
int start_line = 0;
int end_line = 4;
int cur_line = 0;
int i;
fp = fopen("file.txt","r");
while(fgets(buff_line,1024,fp))
{
if (cur_line >= start_line && cur_line <= end_line)
{
memcpy(buffer[cur_line - start_line],buff_line,sizeof(buff_line));
}
cur_line++;
}
for (i=0;i<=(end_line - start_line);i++)
{
fputs(buffer[i],stdout);
}

Related

Allocating unknown char[] in dynamically reading a file in c

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.

Why does the measurement of the size of a file differ from the size of the string that contains it once buffered?

In order to write the content of a file in a buffer, I first need to know the size of the string to allocate. To do this, I use the following function:
long file_length(FILE *fp)
{
if (fp == NULL) return -1L;
fseek(fp, 0L, SEEK_END);
const long len = ftell(fp);
rewind(fp);
return len;
}
And I use it as follows to store the contents of my file:
char *file_content(const char *fname)
{
assert(access(fname, F_OK) != -1);
assert(access(fname, R_OK) != -1);
FILE *fp = fopen(fname, "r");
assert(fp != NULL);
const long flen = file_length(fp);
printf("Length of file: %ld\n", flen);
char *buff = malloc(flen + 1);
assert(buff != NULL);
fread(buff, sizeof(char), flen, fp);
buff[flen + 1] = '\0';
fclose(fp);
return buff;
}
And then I test:
int main()
{
char *content = file_content("test.txt");
printf("Length of buffer: %lld\n", strlen(content));
free(content);
return 0;
}
Here's test.txt:
Hello, world!
This is a simple test.
Stackoverflow.
My program then displays this:
Length of file: 57
Length of buffer: 53
As the file has 4 line feeds, I imagine that the result is related to their interpretation according to the different readings that are made (for the position of the file, with fseek, and for its buffering, with fread). But is it? Or maybe it changes depending on the platform or a reading mode?
If that's the case, so I would like to know how to get the same results, so that I can allocate the exact size of the string directly from my file_length function, without having to subtract the number of line feeds the file contains (if it's possible?) in order to be as optimal as possible.

How to overwrite a file in C?

My question is very simple. I have a file of ascii or binary , whatever. Now, I want every byte in the file to be 0x4f, how can I do it in C ? The question is so simple, but suprisingly, there is no answer on the Internet. I have a sample code, however, there is a dead loop when I run the program:
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ("write_file_2","wb");
unsigned char c = 0x4f;
while(1){
if( feof(pFile) )
break;
int res = fputc(c, pFile);
printf("%d\n", res);
}
fclose (pFile);
return 0;
}
I wonder why the feof() takes no effect.
Thanks!
The problem is that you are using "wb" (w - Create an empty file for output operations), change to "rb+", and use ftell instead of feof (take a look to “while( !feof( file ) )” is always wrong)
#include <stdio.h>
int main(void)
{
FILE * pFile;
long i, size;
unsigned char c = 0x4f;
pFile = fopen("write_file_2", "rb+");
fseek(pFile, 0, SEEK_END);
size = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
for (i = 0; i < size; i++) {
int res = fputc(c, pFile);
printf("%d\n", res);
}
fclose(pFile);
return 0;
}
As soon as you do this pFile = fopen ("write_file_2","wb"); the file is opened and truncated to 0 bytes. So the pFile is at EOF so feof() will return true.
You may want to open it with "r+b", get the size using ftell(), fseek() to 0th position and start writing design data.
Maybe you should firstly check the size of the file :
fseek(f, 0, SEEK_END);
lSize = ftell(f);
fseek(f, 0, SEEK_SET);
Then use 'fwrite' to write desired bytes and number of bytes into the file

convert unsigned int to char alphabets

I have the following code that converts a stream data of 16-bit integer to unsigned 8-bit integer.
I am looking to convert them to alphabetical data values and see what they contain.
#include<stdio.h>
int main() {
FILE *fp,*out;
char buffer[256];
size_t i = 0;
fp=fopen("c:/Gosam/input.txt", "rb");
if(fp != NULL) {
fread(buffer, sizeof buffer,1, fp);
}
out = fopen("c:/Gosam/res.txt", "w");
if(out != NULL) {
// buffer = (char*) malloc (sizeof(char)*Size);
for( i = 0; i < sizeof(buffer); i += 2)
{
const unsigned int var = buffer[i] + 256 * buffer[i + 1];
fprintf(out, "%u\n", var);
}
fclose(out);
}
fclose(fp);
}
The following is the form of my output:
263 4294966987 4294967222 4294967032 64 4294967013 73 4294967004 90
4294967028 83 4294966975 37 4294966961 5 4294966976 82 4294966942
4294967022 4294966994 11 4294967024 29 4294966985 4294966986 4294966954 50
4294966993 4294966974 4294967019 4294967007
This are the values I want to convert to alphabetical characters and see their content.
I don't know what you expect as an answer (you didn't ask a question), but there seems to be one suspicious thing in your code:
char buffer[256];
Here char means signed char. If your code does manipulations on them (like multiplying by 256), it probably doesn't do what you expect (though I can only guess what you expect - your question doesn't mention it).
Try the following:
unsigned char buffer[256];
Also please ask a question (that is, something with a question mark), and give some examples (input, output).
Your basic mistakes were:
after opening the inputfile checking out instead of fp against NULL
fread until eof won't return the number of characters that could be read (I've used fseek and ftell for this purpose)
writing uint values instead of char values to your file
I've fixed them and commented the affected lines appropriate. I also changed the buffer to use dynamic memory allocation instead of static allocation (that's how you can allocate memory for a buffer of a size that is unknown at compile-time). Please try the following code, which will copy all ASCII characters from one file to your output file (which is probably what you meant by 'alphabetical strings'):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
FILE *fp, *out;
char *buffer = NULL; /* use a pointer for dynamic memory allocation */
size_t i = 0, charCount = 0;
fp = fopen("c:/input.txt", "r"); /*read as ascii - not binary */
if(fp != NULL){ /*use 'fp' here 'out' is not initalized */
fseek(fp, 0, SEEK_END); /* go to end of the file */
charCount = ftell(fp) - 1; /* get position */
fseek(fp, 0, SEEK_SET); /* return to the beginning of the file */
buffer = (char*)malloc(sizeof(char)*charCount); /* allocate memory */
fread(buffer, sizeof(char) * charCount, 1, fp); /* reads all characters from the file */
}
out = fopen("c:/output.txt", "w");
if(out != NULL){
for(i = 0; i < charCount; i += 1){ /* loop from 0 to count of characters */
const unsigned char var = buffer[i];
fprintf(out, "%c", var);
}
fclose(out);
}
fclose(fp);
if(buffer != NULL){
free(buffer); /* deallocate memory */
}
return 0;
}

fread fwrite fseek in C

Hello what i am trying to do is to reverse a binary file. The type of the file is wav so for example if the channel number is 2 and bits per sample are 16 each time i will copy 32/8 = 4 bytes. The first think to do is copy the header as it is(that part is ok) and then reverse he data. I've created a code to copy the header and then part of the data from the end this 10 times(for testing) but instead of copying 40 bytes it stops at 20 for some reason(even if it would do it 20 times it would still copy just the 20 bytes). This is the code which does that. I can't spot the mistake if you can see it tell me :) Maybe the mistake is somewhere else so i wrote the full function
void reverse(char **array)
{
int i=0;
word numberChannels;
word bitsPerSample;
FILE *pFile;
FILE *pOutFile;
byte head[44];
byte *rev;
int count;
if(checkFileName(array[2]) == 0 || checkFileName(array[3]) == 0)
{
printf("wrong file name\n");
exit(1);
}
pFile = fopen (array[2] ,"r");
fseek(pFile, 22, SEEK_SET);//position of channel
fread(&numberChannels, sizeof(word), 1, pFile);
fseek(pFile, 34, SEEK_SET);//position of bitsPerSample
fread(&bitsPerSample, sizeof(word), 1, pFile);
count = numberChannels * bitsPerSample;
rewind(pFile);
fread(head, sizeof(head), 1, pFile);
pOutFile = fopen (array[3] ,"w");
fwrite(head, sizeof(head), 1, pOutFile);
count = count/8;//in my example count = 32 so count =4
rev = (byte*)malloc(sizeof(byte) * count);//byte = unsigned char
fseek(pFile, -count, SEEK_END);
for(i=0; i<10 ; i++)
{
fread(rev, count, 1, pFile);
fwrite(rev, count, 1, pOutFile);
fseek(pFile, -count, SEEK_CUR);
}
fclose(pFile);
fclose(pOutFile);
}
sizeof(rev) will evaluate to the size of a pointer. You probably just want to use count instead.
Also, does the line count = count + count do what you want it to? (i.e. it doubles count every iteration)
I would change your fseek to move relatively from the current position (and use count instead of sizeof(rev)):
for(i=0; i<10; i++)
{
fread(rev, count, 1, pFile);
fwrite(rev, count, 1, pOutFile);
fseek(pFile, -count, SEEK_CUR);
}
You need to initialize count to 4 and add 4 to it progressively. Also, sizeof(rev) is only the size of a pointer (4/8 bytes). You need to use sizeof(byte) * count instead. You can also use count in the for directly:
pFile = fopen(array[2] ,"r");
pOutFile = fopen(array[3] ,"w");
rev = (byte*)malloc(sizeof(byte) * count); //byte = unsigned char
for(count = 4; count < 44; count += 4)
{
fseek(pFile, -count, SEEK_END);
fread(rev, sizeof(byte), count, pFile);
fwrite(rev, sizeof(byte), count, pOutFile);
}
fclose(pFile);
fclose(pOutFile);

Resources