I'm trying to add numbering to several lines of text in an existing .txt file using fopen's "r+" mode. This doesnt' seem to work and it ends up writing the first iteration of the string "line" followed by a large amount of junk value. Is there any way to add text at the beginning of a line? If so, am i coming at this the wrong way?
Also im trying to do this without having to write up a whole new file.
void main()
{
char read = ' ';
char buffer[25];
char line[4] = "01."; //lines from 01 to 99
FILE *file;
file = fopen("readme.txt","r+");
if (file == NULL)
{
printf("ERROR: Cannot open input file.\n");
exit();
}
do
{
fwrite(line,strlen(line),1,file);
read=gets(buffer);
if(!feof(file)) // updating line numbers
{
if(line[1]<'9')
{
(line[1])++;
}
else
{
if(line[0]<'9')
{
(line[0])++;
}
else
{
exit();
}
}
}
else
{
exit();
}
}while(!(feof(file)));
fclose(file);
exit();
}
Files in C let you overwrite and append, but not "prepend" data. To insert at the beginning or in the middle, you must copy the "tail" manually.
If you are writing a line-numbering program, it would be much simpler (and faster) to write the result into a separate temporary file, and then copy it in place of the original once the operation is complete.
You can use a simple loop that reads the original file line-by-line, and writes the output file, for example, with fprintf:
fprintf(outFile, "%02d.%s", lineNumber++, lineFromOrigFile);
No, there is no portable/standard way of doing what you want.
Files are random access, but you can't insert data into a file since that would force all the other data to move, which is not an operation supported by typical file systems.
The best solution is to do it in two steps:
Read through the input, while writing output to a new file
Rename the new file to replace the original input
While the answers are correct and you can't add a string in the beginning of a file in C (using only FILE commands), you can interact with the operating system and use bash command 'sed' (in Linux) that solve the problem pretty easily without creating a new file and copy the content of the older file.
void AddTextToFirstLine(const char* file_name, const char* text)
{
char command_string[100]; //Preferably some constant but can be done with malloc of size strlen(text) + strlen(file_name) + 16 (chars in the command + nullbyte)
sprintf(command_string, "sed -i '1 i\\%s' %s", text, file_name);
system(command_string); //executing the sed command
}
You can also look for the equivalent of 'sed' in Unix system for Windows: Is there any sed like utility for cmd.exe?
Although calling the operating system is not recommended usually (because every operating system action stops the program flow and therefore damage time efficiency) This is one of the rare cases in which its ok since we're calling the operating system anyway when we're creating a file (or a copy file in that case). Therefore using this method will also decrease the running time compare to the solution of creating a copy file and copy the content of the old file to it.
Adding string in the beginning of file is just like inserting.
And you can't really directly insert string using C, instead you will overwrite old content.
So you can only do an overhaul to the text file:
record old file content somewhere(temp file or memory...etc), write your string, then paste old content back.
Related
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.
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
}
}
I'm trying to recreate a program I saw in class.
The teacher made a file with 10 lines, he showed us that the file was indeed created, and then he displayed its contents.
My code doesn't work for some reason, it just prints what looks like a"=" a million times and then exits.
My code:
void main()
{
FILE* f1;
char c;
int i;
f1=fopen("Essay 4.txt","w");
for(i=0;i<10;i++)
fprintf(f1," This essay deserves a 100!\n");
do
{
c=getc(f1);
putchar(c);
}while(c!=EOF);
}
What is the problem? as far as I can see I did exactly what was in the example given.
The flow is as such:
You create a file (reset it to an empty file if it exists). That's what the "w" mode does.
Then you write stuff. Note that the file position is always considered to be at the very end, as writing moves the file position.
Now you try to read from the end. The very first thing you read would be an EOF already. Indeed, when I try your program on my Mac, I just get a single strange character just as one would expect from the fact that you're using a do { } while. I suggest you instead do something like: for (c = getc(f1); c != EOF; c = getc(f1)) { putchar(c) } or similar loop.
But also, your reading should fail anyway because the file mode is "w" (write only) instead of "w+".
So you need to do two things:
Use file mode "w+".
Reset the file position to the beginning of the file after writing to it: fseek(f1, 0, SEEK_SET);.
Disclaimer: this is for an assignment. I am not asking for explicit code. Rather, I only ask for enough help that I may understand my problem and correct it myself.
I am attempting to recreate the Unix ar utility as per a homework assignment. The majority of this assignment deals with file IO in C, and other parts deal with system calls, etc..
In this instance, I intend to create a simple listing of all the files within the archive. I have not gotten far, as you may notice. The plan is relatively simple: read each file header from an archive file and print only the value held in ar_hdr.ar_name. The rest of the fields will be skipped over via fseek(), including the file data, until another file is reached, at which point the process begins again. If EOF is reached, the function simply terminates.
I have little experience with file IO, so I am already at a disadvantage with this assignment. I have done my best to research proper ways of achieving my goals, and I believe I have implemented them to the best of my ability. That said, there appears to be something wrong with my implementation. The data from the archive file does not seem to be read, or at least stored as a variable. Here's my code:
struct ar_hdr
{
char ar_name[16]; /* name */
char ar_date[12]; /* modification time */
char ar_uid[6]; /* user id */
char ar_gid[6]; /* group id */
char ar_mode[8]; /* octal file permissions */
char ar_size[10]; /* size in bytes */
};
void table()
{
FILE *stream;
char str[sizeof(struct ar_hdr)];
struct ar_hdr temp;
stream = fopen("archive.txt", "r");
if (stream == 0)
{
perror("error");
exit(0);
}
while (fgets(str, sizeof(str), stream) != NULL)
{
fscanf(stream, "%[^\t]", temp.ar_name);
printf("%s\n", temp.ar_name);
}
if (feof(stream))
{
// hit end of file
printf("End of file reached\n");
}
else
{
// other error interrupted the read
printf("Error: feed interrupted unexpectedly\n");
}
fclose(stream);
}
At this point, I only want to be able to read the data correctly. I will work on seeking the next file after that has been finished. I would like to reiterate my point, however, that I'm not asking for explicit code - I need to learn this stuff and having someone provide me with working code won't do that.
You've defined a char buffer named str to hold your data, but you are accessing it from a separate memory ar_hdr structure named temp. As well, you are reading binary data as a string which will break because of embedded nulls.
You need to read as binary data and either change temp to be a pointer to str or read directly into temp using something like:
ret=fread(&temp,sizeof(temp),1,stream);
(look at the doco for fread - my C is too rusty to be sure of that). Make sure you check and use the return value.
What is the most efficient way to read a big text file backwards, line by line, using Windows API functions? For example, if a file is:
line 1
...
line 108777
line 108778
the output should be:
line 108778
line 108777
...
line 1
I want to write a C program for this. You don't need to write a code (but if you want, that's great), I am just interested in how to do this having in mind that files are big and that I want program to run as fast as it can.
Also, I am interested in which Windows API functions to use.
A more clever solution is to open the file, set the file-offset to the (end of the file - buffersize) and read (buffersize) bytes, u can parse the data in the buffer from back to front to find newlines and do whatever you want, and so on.
If performance is more important than memory utilization, I'd just do a buffered read of the entire text file into memory and then parse it in whatever order you like.
Take a look at memory mapped files, some advantages of which are discussed here.
Memory-map the file. It will be automatically buffered for you - just read it as if it was memory, starting from the tail and looking for CRs / LFs / CRLFs.
Memory mapped files will fail (or at least become very tricky) if the file's bigger than the available address space. Instead, try this:
input = input file
block_prefix = unique temporary file
block_index = 0
while (!eof (input))
{
line = input.readline ();
push line onto a stack
if (stack > 100 entries) // doesn't have to be 100
{
output = block_prefix + block_index++
while (stack has entries)
{
pop line off stack
write to output
}
}
}
if (stack has entries)
{
output = block_prefix + block_index++
while (stack has entries)
{
pop line off stack
write to output
}
}
output = output file
while (block_index)
{
read entire contents of block file (block_prefix + --block_index)
write contents to output
delete block file
}
One method is to use a container of file offsets to the beginning of each line. After parsing the file, process the container in reverse order. See fgetc, fgets and fseek.