C - Append on 2nd line of file - c

Im trying to append on the 2nd line of my txt file. The format I want for my txt file is the following:
1 2 3 4 5
1.2 3.5 6.4 1.2 6.5
Basicly, I want to append on the first two lines of the file.
void write_stats(int tries, int num_letters, int tries_sucess)
FILE *stats;
stats = fopen("C:\\Users\\rjmal\\Documents\\CLION PROJECTS\\JogoDaForca\\stats.txt", "a");
if(stats == NULL)
{
printf("can't open file\n");
exit(0);
}
fprintf(stats," %d\n",tries);
fprintf(stats," %f",(float)tries_sucess/num_letters);
fclose(stats);
}
How do I make that without making a new line on the file everytime I run my program?
With the code I made, I get something like:
1
3 1.5
1 2.3

Due to the way files and lines are considered in computers, you can not vertically print as you desire. Instead, what you can do is storing all these numbers (i.e. tries AND (float)tries_sucess/num_letters) in two arrays and printing the contents of each array on the same line in that order. In effect, this would be buffering your content before printing and formatting it as you desire.
In that way, you can print all the data into two lines, which now correspond to an array, each.
Alternatively, you can create two char arrays and consider them as actual string buffers and use sprintf to record into them. Then, once you're done, you can print each char array through a single fprintf call.
Assuming you created two sufficiently long char arrays, below is a sample code for new write_stats. It now only serves to record the stats into two buffers.
void write_stats(int tries, int num_letters, int tries_sucess, char* buffer1, char* buffer2)
{
sprintf(buffer1 + strlen(buffer1)," %d\n",tries);
sprintf(buffer2 + strlen(buffer2)," %f",(float)tries_sucess/num_letters);
}
Note that you need to initiate the buffers with 0 to be able to easily make use of strlen function as I did. Also, you will eventually (i.e. when you are done calling write_stats ) need to call fprintf, in a block that buffer1 and buffer2 are defined in, as follows.
FILE *stats;
stats = fopen("C:\\Users\\rjmal\\Documents\\CLION PROJECTS\\JogoDaForca\\stats.txt", "a");
if(stats == NULL)
{
printf("can't open file\n");
exit(0);
}
fprintf(stats,"%s\n%s", buffer1, buffer2);
fclose(stats);
Since there are quite a few details to keep in mind, I think it is best you see this idea at work. See here for a working implementation, with some comments to help elaborate some details. As you may observe, the output given there is horizontal and is in 2 lines, as you described and as given below.
1 3 13 55 233
2.000000 1.600000 1.619048 1.617978 1.618037

Related

Strange results with reading binary files in C

I'm working on 64-bit Xubuntu 14.04.
I have a fairly large C program and to test new features, I usually implement them in a separate program to iron out any bugs and whatnot before incorporating them into the main program.
I have a function that takes a const char* as argument, to indicate the path of a file (/dev/rx.bin in this case). It opens the file, reads a specific number of bytes into an array and then does some things before exporting the new data to a different file.
First off I allocate the array:
int16_t samples = (int16_t *)calloc(rx_length, 2 * sizeof(samples[0]));
Note that rx_length is for example 100 samples (closer to 100 000 in the actual program), and it's calculated from the same constants.
Next I open the file and read from it:
uint32_t num_samples_read;
FILE *in_file = fopen(file, "rb");
if (in_file == NULL){
ferror(in_file);
return 1;
}
num_samples_read = fread(samples, 2 * sizeof(samples[0]), rx_length, in_file);
Here's the kicker; the return value from fread is not the same between the test program and the main program, while the code is identical. For example, when I should be reading 100 000 samples from a 400 kB file (100 000 samples, one int16_t for the real part and one int16_t for the imaginary part, adds up to four bytes per sample), the value returned is 99328 in the main program. For the life of me I cannot figure out why.
I've tested the output of every single variable used in any calculation, and up until fread() everything is identical.
I should also note that the function is in a separate header in my main program, but I figured that since printing every constant / definition gives the expected result, that it's not there where I'm making a mistake.
If there's anything that I might have missed, any input would be greatly appreciated.
Regards.
Thank you chux for reminding me to close and answer.
Closing the file was the problem in my main program, it never occurred within the test environment because the input file was not being modified there.
Once the RX thread has completed its task, make a call to fclose():
rx_task_out:
fclose(p->out_file);
// close device
// free sample buffer
return NULL;
Previously, only an error status with creating the RX thread caused it to close the file.

How to save results of a function into text file in C

This function print the length of words with '*' called histogram.How can I save results into text file? I tried but the program does not save the results.(no errors)
void histogram(FILE *myinput)
{
FILE *ptr;
printf("\nsaving results...\n");
ptr=fopen("results1.txt","wt");
int j, n = 1, i = 0;
size_t ln;
char arr[100][10];
while(n > 0)
{
n = fscanf(myinput, "%s",arr[i]);
i++;
}
n = i;
for(i = 0; i < n - 1; i++)
{
ln=strlen(arr[i]);
fprintf(ptr,"%s \t",arr[i]);
for(j=0;j<ln;j++)
fprintf(ptr, "*");
fprintf(ptr, "\n");
}
fclose(myinput);
fclose(ptr);
}
I see two ways to take care of this issue:
Open a file in the program and write to it.
If running with command line, change the output location for standard out
$> ./histogram > outfile.txt
Using the '>' will change where standard out will write to. The issue with '>' is that it will truncate a file and then write to the file. This means that if there was any data in that file before, it is gone. Only the new data written by the program will be there.
If you need to keep the data in the file, you can change the standard out to append the file with '>>' as in the following example:
$> ./histogram >> outfile.txt
Also, there does not have to be a space between '>' and the file name. I just do that for preference. It could look like this:
$> ./histogram >outfile.txt
If your writing to a file will be a one time thing, changing standard out is probably be best way to go. If you are going to do it every time, then add it to the code.
You will need to open another FILE. You can do this in the function or pass it in like you did the file being read from.
Use 'fprintf' to write to the file:
int fprintf(FILE *restrict stream, const char *restrict format, ...);
Your program may have these lines added to write to a file:
FILE *myoutput = fopen("output.txt", "w"); // or "a" if you want to append
fprintf(myoutput, "%s \t",arr[i]);
Answer Complete
There may be some other issues as well that I will discuss now.
Your histogram function does not have a return identifier. C will set it to 'int' automatically and then say that you do not have a return value for the function. From what you have provided, I would add the 'void' before the function name.
void histogram {
The size of arr's second set of arrays may be to small. One can assume that the file you are reading from does not exceed 10 characters per token, to include the null terminator [\0] at the end of the string. This would mean that there could be at most 9 characters in a string. Else you are going to overflow the location and potentially mess your data up.
Edit
The above was written before a change to the provided code that now includes a second file and fprintf statements.
I will point to the line that opens the out file:
ptr=fopen("results1.txt","wt");
I am wondering if you mean to put "w+" where the second character is a plus symbol. According to the man page there are six possibilities:
The argument mode points to a string beginning with one of the
following sequences (possibly followed by additional characters, as
described below):
r Open text file for reading. The stream is positioned at the
beginning of the file.
r+ Open for reading and writing. The stream is positioned at the
beginning of the file.
w Truncate file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.
w+ Open for reading and writing. The file is created if it does
not exist, otherwise it is truncated. The stream is
positioned at the beginning of the file.
a Open for appending (writing at end of file). The file is
created if it does not exist. The stream is positioned at the
end of the file.
a+ Open for reading and appending (writing at end of file). The
file is created if it does not exist. The initial file
position for reading is at the beginning of the file, but
output is always appended to the end of the file.
As such, it appears you are attempting to open the file for reading and writing.

How to stream system() command ouput to any variable

I created a C program which will run some system() commands and save the output to a .txt file in a particular folder of C drive (program is to be run on domain clients with startup privileges), from where I'll filter the data and show it on output console screen.
Everything worked fine, but I couldn't design it for those PCs who have OS installed in other drives (e.g. D:, E:, etc), since they will not have this particular folder in their C: drive. I can't write temporary .txt files anywhere else due to group policies.
Is there any method to stream this data directly into any array variable? I went through popen() function, but it would require a very large array of unpredicted size to be defined (since the output of system() command may be very large). For example, exporting the registry keys of HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\uninstall into a .txt file. Its size may be up to 50KB or bigger.
reg export HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\uninstall C:\\..(somewhere)....\\reg_output.txt
There are some more similar commands with large output. I don't know Win API programming yet, thus I am using system command. Can there be an easy alternative to writing to .txt ?
#Megharaj!
As you used
char line[100];
fp = popen("ifconfig eth0", "r");
fgets(line, 100, fp);
I'll have to use
char reg_output[100000];
fp=popen("reg export HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\uninstall ????","r");
fgets(line,100000,fp);
Where do I export the registry values? (Since the DOS command for exporting this needs to write it to a file), as compared to following code I am using.
Assigning a space of 100000 isn't sure that it will not be error prone. And assigning too high value also will affect the memory on startup (I'm not sure but guess so).
While using file handling I do it as:
char line[5000]; FILE* fp_reg; int ch,n=0;
system("reg export HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\uninstall c:\\registries.txt");
fp_reg=fopen("c:\\registries.txt","r");
while((ch=fgetc(fp_reg))!=EOF)
{
if(isalnum(ch) || ch=='\n') //allow only alpha numeric & '\n' to pass to array
{ line[n]=ch;
if(ch=='\n')
{ filter_for_software(line,n); //Send the array for filtering function
n=0; // Reset the array 'line'
}
n++;
}
}
(I didn't copy the code from source, since I am sitting on a different PC. But the code is almost similar to this. Some errors may come if you copy this code & run.)
This way, I take each line from file and send it for filtering to get 'installed software's name'. How do I do it with 'popen()', so that I could pick up a line and throw it onto a function. Plz write some code also for this.
If you want to store the output in an array, you will have to allocate an array of appropriate size. There is just no way around that.
But you don't need to do that if you use popen. You get a FILE * handle and can just read the output in small parts and process it on the go.
from where I'll filter the data and show it on output console screen.
How do you do that? With the shell or in C? If in C, then you read the output of the systemed command just like you would read your txt file. The only difference is that you need to close it with pclose instead of fclose, so there are only advantages to doing it with a text file.
If in shell, then you can start the program you use with another call to popen, this time in a "w" (write) direction and write the output of one pipe as input to the other. However, in this case you could have just called a shell with an anonymous pipe in the first place. ;-)
Edit:
Your own answer makes clear that your requirements are quite different from what you think they are. There is no way to read the output of reg export back via a pipe and popen if it insists on writing to a file.
What you can try is to write a file to your temp folder; you should be allowed to create files there, otherwise Windows will not work correctly. Just specify something like "%TEMP%\reg.out" as file and read your data back from there.
If that doesn't work, you are out of luck with reg export. But you can use some Windows API function for querying the registry directly. Here is a starting point.
Alternatively, you might want to look into the possibility of employing PowerShell. This question might be of interest to you.
In linux to use the values from the system command i use popen, I am just giving an example of code that I had written some time long back, to get the ip address of the pc by system command "ifconfig eth0" to the string/a file. see the example
void get_my_ip(char *ip_mac_address)
{
FILE *fp,*output;
char *start=NULL;
char *end=NULL;
char line[100];
output=fopen("my_ip_address.txt", "w");
if(output == NULL) {
printf("error creating outputfile\n");
return -1;
}
printf("program to self query the ip address\n");
fp = popen("ifconfig eth0", "r");
fgets(line, 100, fp);
start=strstr(line, CHECK_STRING_MAC);
start = start + 7;
fwrite(start, 1, 17, output); start = NULL;
fgets(line, 100, fp);
start=strstr(line, CHECK_STRING_IP);
start = start + 10;
fwrite(start, 1, 14, output);
fclose(output);
pclose(fp);
if( access("my_ip_address.txt", F_OK ) != -1 ) {
printf("found file having ip address\n");
output=fopen("my_ip_address.txt", "r");
fgets(ip_mac_address, 32, output);
}
else
printf("unabe to find file with ip address\n");
fclose(output);
printf("my ip and mac address adress is %s \n",ip_mac_address);
}
You can create a temporary file using some API from Windows, and store your data in it.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363875(v=vs.85).aspx
There is a C++ example in the link, you should be able to adapt it to your case.
So, I prepared the code to stream the output of a DOS command to a file pointer in read mode and check it line by line:
char array_sys[200]; FILE *fp_sys; int ch,n=0;
fp=popen("systeminfo","r"); //runs a DOS command & read it with a file pointer
if(fp_sys==NULL) printf("can't open file\n");
while((ch=fgetc(fp_sys))!=EOF) //READ CHARACTERS FROM FILE POINTER UNTIL FILE ENDS
{
array_sys[n]=ch; //ASSIGN CH TO EACH ELEMENT OF ARRAY
n++; //INCREMENT ELEMENTS OF ARRAY:-arr_sys
if(ch=='\n') //IF ELEMENTS MEET A NEW LINE CHARACTER
{
disp_date(array_sys,n); //PASS ARRAY TO FUNCTION:-disp_date
n=0; //RESET THE ARRAY
}
}
Now this is how I process array in function to get the name of operating system.
void disp_date(char array_sys[],int ind)
{
char os_name[9]={"OS Name:"};
if(strstr(array_sys,os_name)) //IF 'OS NAME' IS PRESENT IN ARRAY
{
printf("%s",array_sys); //PRINT THE ARRAY
}
}

C - read specific line from file

I'm trying to read a specific line from a file and I can get the line number but I'm not sure how to go about doing it, this is what I have so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *file;
file = fopen("temp.txt","r");
char tmp[256]={0x0};
char *tmpline;
int numline = 1;
while(file != NULL && fgets(tmp, sizeof(tmp),file) !=NULL)
{
tmpline = strstr(tmp,"status:green");
if(tmpline) {
printf("%d - %s", numline, tmpline);
}
numline++;
}
if (file != NULL) fclose(file);
return 0;
}
The test file looks like:
s1.server.com
127.0.0.1
status:green
s2.server.com
127.0.0.1
status:red
s3.server.com
127.0.0.1
status:red
s4.server.com
127.0.0.1
status:green
The output that I have is:
3 - status:green
15 - status:green
But what I really want it to show is:
s1.server.com
s4.server.com
I want it to search for "status:green" then go back a few lines to show which server it belongs to
It sounds as if you need to do one of two things.
Simpler option: keep a little circular buffer of lines. Read into line 0, line 1, line 2, ..., line n-1, line 0, line 1, etc. Then, when you see the text you want, look in entry (current_index - 2) mod buffer_size. (Here it sounds as if a buffer size of 3 will suffice.)
More sophisticated option: actually parse the input so that for each block you work out the server name, its IP address and its status, and then display the information you need using that.
The "more sophisticated option" would be substantially more work, but more robust if the syntax of your input ever changes (e.g., with optional extra lines with more information about the server -- multiple IP addresses or multiple names, perhaps).
There are some other things you could do that I think are worse. (1) Call ftell on each line and put the results of that in a circular buffer, and then use fseek when you see "status:green". (2) Read the whole file using code like you currently have, building up a list of "good" servers' line numbers. Then go through the file again and report the good ones. I think these are both uglier and less efficient than the approaches I listed above. There's one possible advantage: you can adapt them to count in "stanzas" separated by blank lines, without needing to parse things properly. That would get you part of the flexibility of the "more sophisticated" approach I mentioned, without needing a proper parser.
And here's a hybrid possibility: don't use a circular buffer, but one whose size can increase if need be. Start at the first entry in the buffer each time you see a blank line. Let the buffer grow if there are "long" stanzas. Then when you see "status:green", do whatever processing you need to on the (presumably complete) stanza now held in your buffer.
None of the above is necessary, of course, if you're sure that the file format will never change.
If the test file (and production file) is well-formed then you can do something like the following (error checking left out for brevity!):
typedef struct _SERVERSTATUS
{
char* name;
char* ip;
char* status;
} SERVERSTATUS;
SERVERSTATUS ss;
ss.name = calloc(256);
ss.ip = calloc(256);
ss.status = calloc(256);
while (!feof(file))
{
fgets(ss.name, file);
fgets(ss.ip, file);
fgets(ss.status, file);
if (!strcmp(ss.status, "status:green"))
printf("%s\n", ss.name);
}
free(ss.name);
free(ss.ip);
free(ss.status);
Edit: You also have to handle the whitespace between the file entries! That's, um, left as an exercise for the questioner
Read the first and third lines in each group. Search for status:green and, if found, print the server name.

Opening a file in C through a proccess

I am trying to create a a program that does the following actions:
Open a file and read one line.
Open another file and read another line.
Compare the two lines and print a message.
This is my code:
#include <stdio.h>
#include <string.h>
int findWord(char sizeLineInput2[512]);
int main()
{
FILE*cfPtr2,*cfPtr1;
int i;
char sizeLineInput1[512],sizeLineInput2[512];
cfPtr2=fopen("mike2.txt","r");
// I open the first file
while (fgets(sizeLineInput2, 512, cfPtr2)!=NULL)
// I read from the first 1 file one line
{
if (sizeLineInput2[strlen(sizeLineInput2)-1]=='\n')
sizeLineInput2[strlen(sizeLineInput2)-1]='\0';
printf("%s \n",sizeLineInput2);
i=findWord(sizeLineInput2);
//I call the procedure that compares the two lines
}
getchar();
return 0;
}
int findWord(char sizeLineInput2[512])
{
int x;
char sizeLineInput1[512];
File *cfPtr1;
cfPtr1=fopen("mike1.txt","r");
// here I open the second file
while (fgets(sizeLineInput1, 512,cfPtr1)!=NULL)
{
if (sizeLineInput1[strlen(sizeLineInput1)-1]=='\n')
sizeLineInput1[strlen(sizeLineInput1)-1]='\0';
if (strcmp(sizeLineInput1,sizeLineInput2)==0)
//Here, I compare the two lines
printf("the words %s and %s are equal!\n",sizeLineInput1,sizeLineInput2);
else
printf("the words %s and %s are not equal!\n",sizeLineInput1,sizeLineInput2);
}
fclose(cfPtr1);
return 0;
}
It seems to have some problem with file pointers handling. Could someone check it and tell me what corrections I have to do?
Deconstruction and Reconstruction
The current code structure is, to be polite about it, cock-eyed.
You should open the files in the same function - probably main(). There should be two parallel blocks of code. In fact, ideally, you'd do your opening and error handling in a function so that main() simply contains:
FILE *cfPtr1 = file_open("mike1.txt");
FILE *cfPtr2 = file_open("mike2.txt");
If control returns to main(), the files are open, ready for use.
You then need to read a line from each file - in main() again. If either file does not contain a line, then you can bail out with an appropriate error:
if (fgets(buffer1, sizeof(buffer1), cfPtr1) == 0)
...error: failed to read file1...
if (fgets(buffer2, sizeof(buffer2), cfPtr2) == 0)
...error: failed to read file2...
Then you call you comparison code with the two lines:
findWord(buffer1, buffer2);
You need to carefully segregate the I/O operations from the actual processing of data; if you interleave them as in your first attempt, it makes everything very messy. I/O tends to be messy, simply because you have error conditions to deal with - that's why I shunted the open operation into a separate function (doubly so since you need to do it twice).
You could decide to wrap the fgets() call and error handling up in a function, too:
const char *file1 = "mike1.txt";
const char *file2 = "mike2.txt";
read_line(cfPtr1, file1, buffer1, sizeof(buffer1));
read_line(cfPtr2, file2, buffer2, sizeof(buffer2));
That function can trim the newline off the end of the string and deal with anything else that you want it to do - and report an accurate error, including the file name, if anything goes wrong. Clearly, with the variables 'file1' and 'file2' on hand, you'd use those instead of literal strings in the file_open() calls. Note, too, that making them into variables means it is trivial to take the file names from the command line; you simply set 'file1' and 'file2' to point to the argument list instead of the hard-wired defaults. (I actually wrote: const char file1[] = "mike1.txt"; briefly - but then realized that if you handle the file names via the command line, then you need pointers, not arrays.)
Also, if you open a file, you should close the file too. Granted, if your program exits, the o/s cleans up behind you, but it is a good discipline to get into. One reason is that not every program exits (think of the daemons running services on your computer). Another is that you quite often use a resource (file, in the current discussion) briefly and do not need it again. You should not hold resources in your program for longer than you need them.
Philosophy
Polya, in his 1957 book "How To Solve It", has a dictum:
Try to treat symmetrically what is symmetrical, and do not destroy wantonly any natural symmetry.
That is as valid advice in programming as it is in mathematics. And in their classic 1978 book 'The Elements of Programming Style', Kernighan and Plauger make the telling statements:
[The] subroutine call permits us to summarize the irregularities in the argument list [...]
The subroutine itself summarizes the regularities of the code.
In more modern books such as 'The Pragmatic Programmer' by Hunt & Thomas (1999), the dictum is translated into a snappy TLA:
DRY - Don't Repeat Yourself.
If you find your code doing the 'same' lines of code repeated several times, write a subroutine to do it once and call the subroutine several times.
That is what my suggested rewrite is aiming at.
In both main() and findWord() you should not use strlen(sizeLineInputX) right after reading the file with fgets() - there may be no '\0' in sizeLineInput2 and you will have strlen() read beyond the 512 bytes you have.
Instead of using fgets use fgetc to read char by char and check for a newline character (and for EOF too).
UPD to your UPD: you compare each line of mike2.txt with each line of mike1.txt - i guess that's not what you want. Open both files one outside while loop in main(), use one loop for both files and check for newline and EOF on both of them in that loop.

Resources