yyin = fopen("input_file.txt","r");
while ((nread = fread(buf, 1, sizeof buf, yyin)) > 0){
fwrite(buf, 1, nread, stdout);
}
fclose(yyin);
yyin = fopen("input_file.txt","r");
yyparse();
fclose(yyin);
As you see, I open multiple times the same file. First I want to print the output in my cmd/terminal; then I want to start the parser. The problem is obvious: Each opening process costs resources, but the combination of fread and fwrite seems to "clean" my input file so that yyparse does not get any further input and basically stays empty.
Do you have any idea of how to make this more performant or smooth with out 2 file openings?
You can use rewind() to return to the beginning of the file again. See this documentation for more details.
Related
what I want to do is open a file(which is huge) and read from a certain point of bytes to an offset.
in c# this can be done with:
File.ReadAllBytes(file).Skip(50).Take(10).ToArray();
the problem with this is that it reads the entire file but since my files can be huges this also takes a long time. is there a way to read parts of a file similiar to this method but WITHOUT reading the entire file? In c preferably
Yes, use the fseek() standard library function to move ("seek") to the desired position:
FILE *in = fopen("myfancyfile.dat", "rb");
if(fseek(in, 50, SEEK_SET) == 0)
{
char buf[10];
if(fread(buf, sizeof buf, 1, in) == 1)
{
/* got the data, process it here */
}
}
fclose(in);
Okay so this is probably has an easy solution, but after a bit of searching and testing I remain confused.. :(
Here is a snippet of the code that I have written:
int main(int argc, char *argv[]){
int test;
test = copyTheFile("test.txt", "testdir");
if(test == 1)
printf("something went wrong");
if(test == 0)
printf("copydone");
return 0;
}
int copyTheFile(char *sourcePath, char *destinationPath){
FILE *fin = fopen(sourcePath, "r");
FILE *fout = fopen(destinationPath, "w");
if(fin != NULL && fout != NULL){
char buffer[10000];//change to real size using stat()
size_t read, write;
while((read = fread(buffer, 1, sizeof(buffer), fin)) > 0){
write = fwrite(buffer, 1, read, fout);
if(write != read)
return 1;
}//end of while
}// end of if
else{
printf("Something wrong getting the file\n");
return 0;}
if(fin != NULL)
fclose(fin);
if(fout != NULL)
fclose(fout);
return 0;
}
Some quick notes: I am very new to C, programming, and especially file I/O. I looked up the man pages of fopen, fread, and fwrite. After looking at some example code I came up with this. I was trying to just copy a simple text file, and then place it in the destination folder specified by destinationPath.
The folder I want to place the text file into is called testdir, and the file I want to copy is called test.txt.
The arguments I have attempted to use in the copyFile function are:
"test.txt" "testdir"
".../Desktop/project/test.txt" ".../Desktop/project/testdir"
"/Desktop/project/test.txt" "/Desktop/project/testdir"
I just get the print statement "Something wrong getting the file" with every attempt. I am thinking that it may be because 'testdir' is a folder not a file, but then how would I copy to a folder?
Sorry if this a really basic question, I am just having trouble so any advice would be awesome!
Also, if you wanted to be extra helpful, the "copyTheFile" function is supposed to copy the file regardless of format. So like if its a .jpg or something it should copy it. Let me know if any of you guys see a problem with it.
This is with ISO/POSIX/C89/C99 on Linux.
At the start, you'll want to include stdio.h to provide FILE and the I/O function declarations:
#include <stdio.h>
Aside from this, your program compiles and works properly for me. Unfortunately you can't copy to a directory without using stat() to detect if the destination is a directory, and if so, appending a file name before opening the file.
Some other minor suggestions:
A buffer with a power of two bytes such as 4096 is probably more efficient due to it lining up with filesystem and disk access patterns
Conventionally, C functions that return a status code use 0 for success and other values such as 1 for failure, so swapping your return values may be less confusing
When a standard library function such as fopen, fread or fwrite fails, it is a good idea to use perror(NULL); or perror("error prefix"); to report it, which may look something like:
$ ./a.out
...
error prefix: No such file or directory
if you are trying to write a new file in a directory, you should be giving the full path of the file to be written. in your case
"C:...\Desktop\project\testdir\testfile"
Okay so I have a program and it adds new entries to a structure to a .dat file. I know when appending it adds to the end of the list. This works fine. The problem I am having is that I have a tracking variable that keeps track of the length of the struct. I can bring back the items in the struct but how do I bring back the variable that is keeping track of the length. You can't find it's length either so I would have to bring back a variable. I was thinking leave the first line of the .dat file just for the tracking variable but I don't know if you can append just the first line.
Bellow is of course what I am using to add in items to my struct. Above it would be num ++ which means the length of the struct increased by one.
if ( pWrite != NULL ) {
fprintf(pWrite, "%s %s %s\n", info2[nume].first, info2[nume].last, info2[nume].number);
fclose(pWrite);
} else {
perror("The following error occurred");
exit(EXIT_FAILURE); //exit program with error
}
Not sure if I am leaving anything out. Any help would be great. Thanks!
Store an integer in the file which represents the amount of structs you have in the file.
[integer]xxxxxxxxxxxxxxxxxxxxxx
or
xxxxxxxxxxxxxxxxxxxxxx[integer]
In the both cases, updating would require the r+ flag when opening the file (→ fopen). Then, you can simply read and then overwrite the integer.
// This may not work - my C skills got worse over the time :)
FILE *f = fopen("test.dat", "r+");
fread(buffer, sizeof(int), 1, f);
fseek(f, 0, SEEK_START);
fwrite(buffer, sizeof(int), 1, f);
If the elements of the struct are of known length, then you can look at the file size and compute how many elements there must be. That is the easiest way to accomplish what you are asking.
EDIT After reading other attempted answers, and your comments, here is something that might work better for you - random file access. The following illustrates this:
FILE *fp;
int myCounter = -1;
fp = fopen("myFile.dat", "wb"); // want to write
fwrite(&myCounter, sizeof(int), 1, fp); // write size of -1 to start of file: "unknown count"
fprintf(fp, "Now I write something");
fseek(fp, 0, SEEK_SET); // point file to beginning
myCounter=1;
fwrite(&myCounter, sizeof(int), 1, fp); // write the new size: 1
fseek(fp, 0, SEEK_END); // back to the end of the file
fprintf(fp, "Here is something else");
... etc
It should be obvious how you can wrap this into a loop - note though that it would be slow to update the file counter on every write, since the disk will be "hunting" from one sector to another. So better write until you have no more to write, then update the counter at the start of the file with the fseek command. You do need to do the first write just to make sure you leave space. I chose to write -1 as this would indicate to the reading program "no valid size has been written". Usually good to put some error checking like that in your code...
If you haven't saved the variable's value somehow/somewhere (for example, written to a file), and can't recompute it from what you HAVE saved, its gone.
I'm trying to write PCM data (in a separate file) to the wav file I'm creating. I have already written the header and confirmed that worked but for some reason when I try to write the raw data into it, it doesn't. What I have successfully read the pcm file to a buffer and got the size of the file. The fwrite() process didn't give me an error either during compile however the resulting file is still empty. Any help is much appreciated! Thanks!
register FILE *handle;
register FILE *lever;
char filename[] = "test.wav";
handle = fopen(filename, "w");
lever = fopen("test.pcm","rb");
fseek(lever, 0, SEEK_END);
long int lSize = ftell(lever);
printf("%i \n",lSize);
rewind(lever);
char *buffer = (char*) malloc(sizeof(char)*lSize);
if (NULL == buffer) {printf("Error creating buffer \n");}
if (lSize != fread(buffer, 1, lSize, lever)) {
printf("Reading error \n");
}
fwrite(buffer, sizeof(buffer), 1, handle);
free(buffer);
fclose(lever);
fclose(handle);
Change
fwrite(buffer, sizeof(buffer), 1, handle);
into:
fwrite(buffer, lSize, 1, handle);
If you are running this under windows, it could fail because of text mode output file.
Use handle = fopen(filename, "wb");. Are you sure you have no errors while opening the files? Also your way of getting file size isn't optimal and it's better to use stat-family functions. And if malloc will fail you'll get a "Segmentation fault".
fwrite returns number of items written, or -1 on error. It sets errno so you can use perror or strerror.
EDIT: wildplasser's answer is the correct solution. Didn't notice this mistake.
I have written a program which takes a file as input and whenever it finds a line with length > 80, it adds \ and \n to that file to make it 80 chars in width max.
The problem is that I have used fseek to insert \ and \n whenever the length exceeds 80, so it overrides two characters of that line which exceeds length 80. Is there a way using which I can insert text without overriding the existing text?
Here is my code:-
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
FILE *fp1,*fp2;
int prev=0,now=0;
char ch;
int flag=0;
long cur;
fp1=fopen(argv[1],"r+");
if(fp1==NULL){
printf("Unable to open the file to read. Program will exit.");
exit(0);
}
else{
while((ch=fgetc(fp1))!=EOF){
if(ch!=' ' && ch!='\n'){
now=now+1;
}
else{
if(now>=80){
fseek(fp1,cur,SEEK_SET);
fputc('\\',fp1);
fputc('\n',fp1);
now=0;
continue;
}
if(ch=='\n'){
flag=0;
now=0;
continue;
}
else{
prev=now;
cur=ftell(fp1);
}
now=now+1;
}
}
}
fclose(fp1);
return 0;
}
To run it, you need to do following:-
user#ubuntu$ cc xyz.c
user#ubuntu$ ./a.out file_to_check.txt
While there are a couple of techniques to do it in-place, you're working with a text file and want to perform insertions. Operating systems typically don't support text file insertions as a file system primitive and there's no reason they should do that.
The best way to do that kind of thing is to open your file for reading, open a new file for writing, copy the part of the file before the insertion point, insert the data, copy the rest, and then move the new file over the old one.
This is a common technique and it has a purpose. If anything goes wrong (e.g. with your system), you still have the original file and can repeat the transaction later. If you start two instances of the process and use a specific pattern, the second instance is able to detect that the transaction has already been started. With exclusive file access, it can even detect whether the transaction was interrupted or is still running.
That way is much less error prone than any of the techniques performed directly on the original file and is used by all of those traditional tools like sed even if you ask them to work in-place (sed -i). Another bonus is that you can always rename the original file to one with a backup suffix before overwriting it (sed offers such an option as well).
The same technique is often used for configuration files even if your program is writing an entirely new version and doesn't use the original file for that. It hasn't been long since many internet magazines claimed that ext4 accidentally truncates configuration files to zero length. This was exactly because some applications kept the configuration files open and truncated while the system was forcedly shut down. Those application often tampered with the original configuration files before they had the data ready and then even kept them open without syncing them, which made the window for data corruption much larger.
TL;DR version:
When you value your data, don't destroy it before you have the replacement data ready.
No, there's no way to insert characters into an existing file. You will need to use a second file to do that.
This is the function I use for this kind of thing:
int finsert (FILE* file, const char *buffer) {
long int insert_pos = ftell(file);
if (insert_pos < 0) return insert_pos;
// Grow from the bottom
int seek_ret = fseek(file, 0, SEEK_END);
if (seek_ret) return seek_ret;
long int total_left_to_move = ftell(file);
if (total_left_to_move < 0) return total_left_to_move;
char move_buffer[1024];
long int ammount_to_grow = strlen(buffer);
if (ammount_to_grow >= sizeof(move_buffer)) return -1;
total_left_to_move -= insert_pos;
for(;;) {
u16 ammount_to_move = sizeof(move_buffer);
if (total_left_to_move < ammount_to_move) ammount_to_move = total_left_to_move;
long int read_pos = insert_pos + total_left_to_move - ammount_to_move;
seek_ret = fseek(file, read_pos, SEEK_SET);
if (seek_ret) return seek_ret;
fread(move_buffer, ammount_to_move, 1, file);
if (ferror(file)) return ferror(file);
seek_ret = fseek(file, read_pos + ammount_to_grow, SEEK_SET);
if (seek_ret) return seek_ret;
fwrite(move_buffer, ammount_to_move, 1, file);
if (ferror(file)) return ferror(file);
total_left_to_move -= ammount_to_move;
if (!total_left_to_move) break;
}
seek_ret = fseek(file, insert_pos, SEEK_SET);
if (seek_ret) return seek_ret;
fwrite(buffer, ammount_to_grow, 1, file);
if (ferror(file)) return ferror(file);
return 0;
}
Use it like this:
FILE * file= fopen("test.data", "r+");
ASSERT(file);
const char *to_insert = "INSERT";
fseek(file, 3, SEEK_SET);
finsert(file, to_insert);
ASSERT(ferror(file) == 0);
fclose(file);
This (as others here have mentioned) can theoretically corrupt a file if there is an error, but here is some code to actually do it... Doing it in-place like this is usually fine, but you should backup the file if you are worried about it...
No, there is no way. You have to create a new file or move the contents of the file 2 characters backwards.
You can load the file as chunks (in your case is 80 characters) and then append two character (new line) and write the content into anohter file.
another implementation use tmpfile()
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
FILE *tmp_buf;
int finsert(FILE *f, const char* msg){
fseek(tmp_buf, 0, SEEK_SET);
fpos_t f_pos;
assert (fgetpos(f, &f_pos)==0);
char buf[50];
while(fgets(buf, 50, f))
fputs(buf, tmp_buf);
long tmp_buf_pos = ftell(tmp_buf);
fsetpos(f, &f_pos);
fputs(msg, f);
fseek(tmp_buf, 0, SEEK_SET);
while(--tmp_buf_pos>=0)
fputc(fgetc(tmp_buf), f);
return ferror(f);
}
int main()
{
FILE *f = fopen("result.txt", "wb+");
assert (f!=NULL);
fputs("some text", f);
tmp_buf = tmpfile();
assert (tmp_buf!=NULL);
assert(finsert(f, "another text")==0);
fclose (f);
perror("");
}
tested in Cygwin64