I want to write a program that reads the lines in a text file and sorts them by length. After reading the file, I want to output the contents into the command line and an output file. I also want to use the text files as arguments of the command-line.
These are my created sentences for trials
1. hello world
2. john doe at the bay watch
3. Great Heavens
4. altair
5. Jim and Jamy
my source.c
int main(void) {
FILE* fread = fopen("C:\\Users\\Peter\\desktop\\input.txt", "r");
FILE* fwrite = fopen("C:\\Users\\Peter\\desktop\\output.txt", "w");
if (fread == NULL || fwrite == NULL) {
printf("One file wouldn't open!\n");
return -1;
}
//(1.) this copies the text from input.txt to output.txt
char c;
while ((c = fgetc(fread)) != EOF) {
fputc(c, fwrite);
}
//(2.) this pastes the text from input.txt into the command-line
char line[1000] = "";
while (fscanf(fread, "%s", line) == 1) {
printf("%s\n", line);
}
fclose(fread);
fclose(fwrite);
}
Results
output.txt
1. hello world
2. john doe at the bay watch
3. Great Heavens
4. altair
5. Jim and Jamy
terminal / command-line
1.
hello
world
2.
john
doe
at
the
bay
watch
3.
Great
Heavens
4.
altair
5.
Jim
and
Jamy
My problems are:
For (1.) and (2.) only one works at the time. so if I switch them around the other one doesn't work anymore
The command-line ignores spaces and uses that as a new line
I wouldn't know how to sort the strings by length (1-2-3-4-5 into 2-3-5-1-4)
Pasting the second order in the output.txt file and the command-line at the same time
Related
I've been trying to figure out how I would, read a .txt file, and pick a line of said file from random then write the result to a different .txt file
for example:
.txt
bark
run
car
take line 2 and 3 add them together and write it to Result.txt on a new line.
How would I go about doing this???
I've tried looking around for resources for fopen(), fgets(), fgetc(), fprintf(), puts(). Haven't found anything so far on reading a line that isn't the first line, my best guess:
-read file
-print line of file in memory I.E. an array
-pick a number from random I.E. rand()
-use random number to pick a array location
-write array cell to new file
-repeat twice
-make newline repeat task 4-6
-when done
-close read file
-close write file
Might be over thinking it or just don't know what the operation to get a single line anywhere in a file is.
just having a hard time rapping my head around it.
I'm not going to solve the whole exercise, but I will give you a hint on how to copy a line from one file to another.
You can use fgets and increment a counter each time you find a line break, if the line number is the one you want to copy, you simply dump the buffer obtained with fgets to the target file with fputs.
#include <stdio.h>
#include <string.h>
int main(void)
{
// I omit the fopen check for brevity
FILE *in = fopen("demo.c", "r");
FILE *out = fopen("out.txt", "w");
int ln = 1, at = 4; // copy line 4
char str[128];
while (fgets(str, sizeof str, in))
{
if (ln == at)
{
fputs(str, out);
}
if (strchr(str, '\n') && (ln++ == at))
{
break;
}
}
fclose(in);
fclose(out);
return 0;
}
Output:
int main(void)
I need to write two variables to a text file with a space in between them, what I want my text file to look like:
log.txt
www.google.com feb17202101
www.yahoo.com feb17202102
www.xyz.com feb17202103
The domain name and dates are stored in two char arrays.
My code
FILE *fp;
fp = fopen("log.txt", "w+");
if(fp == NULL)
{
printf("Could not open file 31");
exit(0);
}
fprintf(fp,"%s %s\n",domainName, fileName);
(DomainName and fileName are two separate char arrays)
I was hoping this would print both my variables with a space in between them and go onto the next line so when my function needs to write to the text file again, it will be on a fresh line.
Instead my text file looks like
www.google.com
022321224825
This seems like it should be the easiest part of my program but it's one of those days where I spent all day coding and now my brain feels fried haha. I can't figure out how to format it properly. If someone could help me out, I would appreciate it!
As pointed out in comment, I think you have a newline character in domainname array itself. When I try to write two simple arrays to a file like this;
char domainNames[3][20] = {"www.google.com", "www.yahoo.com", "www.xyz.com"};
char timestamps[3][20] = {"feb17202101", "feb17202102", "feb17202103"};
for (int i = 0; i < 3; i++) {
fprintf(fp,"%s %s\n",domainNames[i], timestamps[i]);
}
This prints the following output:
c-posts : $ cat log.txt
www.google.com feb17202101
www.yahoo.com feb17202102
www.xyz.com feb17202103
If you're getting domainname and timestamp from user input using fgets(), a newline character gets added at the end. You might want to trim it:
void trimTrailingNewline(char input[]) {
input[strcspn(input, "\n")] = 0;
}
Then you can use it to remove trailing newlines in either before writing to file or after reading as user input:
for (int i = 0; i < 3; i++) {
trimTrailingNewline(domainNames[i]);
trimTrailingNewline(timestamps[i]);
fprintf(fp,"%s %s\n", domainNames[i], timestamps[i]);
}
I want to change lines which contain the # symbol in a text file with heet using C.
I have tried it this way, but it did not work thoroughly, it just replaces the characters & overwrites not the whole string, like I want.
Is there any other trick to remove or delete a whole line from the file? So, we can easily replace it.
myfile.txt: (before execution)
Joy
#Smith
Lee
Sara#
Priyanka
#Addy
Code:
#include <stdio.h>
#include <string.h>
int main() {
FILE *pFile;
fpos_t pos1, pos2;
int line = 0;
char buf[68]
char *p;
char temp[10] = "heet";
pFile = fopen("myfile.txt", "r+");
printf("changes are made in this lines:\t");
while (!feof(pFile)) {
++line;
fgetpos(pFile, &pos1);
if (fgets(buf, 68, pFile) == NULL)
break;
fgetpos(pFile, &pos2);
p = strchr(buf, '#');
if (p != NULL) {
printf("%d, " , line);
fsetpos(pFile, &pos1);
fputs(temp, pFile);
}
fsetpos(pFile, &pos2);
}
fclose(pFile);
return 0;
}
myfile.txt: (after execution)
Joy
heetth
Lee
heet#
Priyanka
heety
Output:
changes are made in this lines: 2, 4, 6,
myfile.txt: (I want to get)
Joy
heet
Lee
heet
Priyanka
heet
The best way of doing what you want is to use a utility like sed. It is faster and uses less memory than anything you (or I) would write.
That aside, let's assume you want to go ahead and write it yourself anyway.
A file is just like a long array of bytes. If you want to increase or decrease the length of one line, it affects the position of every byte in the rest of the file. The result can be shorter (or longer) than the original. As the result can be shorter, modifying the file in place is a bad idea.
The following pseudo-code illustrates a simple approach:
open original file
open output file
allocate a line buffer that is large enough
read a line from the original file
do
return an error if the buffer is too small
manipulate the line
write the manipulated line to the output file
read a line from the original file
loop until read returns nothing
sed does it much smarter. I once saw an explanation on how sed works, but my google karma can't seem to find it.
Edit:
How to do it using sed:
sed -e 's/.*\#.*/heet/g' myfile.txt
The s, or substitute, command of sed can replace one string, or regular expression, with another string.
The above command is interpreted as:
replace any line that has a # somewhere in it with heet. The final g tells sed to do this globally, i.e. in the entire file.
Edit2:
By default, sed writes to standard output.
To rewrite the file you should redirect the output to a file and then rename it.
In linux, do the following (you can run command line stuff from C with system):
sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt
rm myfile.txt
mv temp_file123.txt myfile.txt
From C:
system("sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt");
system("rm myfile.txt");
system("mv temp_file123.txt myfile.txt");
If you want to do it with just one call to system, put all the command line stuff in a shell script.
You should probably treat input/output like a UNIX utility and replace the line by reading in the whole input and writing the whole output like sed would or something. It's going to be a pain to edit the line in place as you need to shift the following text 'down' in order to make it work.
You cannot achieve your goal by overwriting the file in place like you do in the code because heet is 3 bytes longer than # and there is no standard function to insert bytes in the middle of a file.
Note also these important issues:
you do not test if fopen() succeeds at opening the file. You have undefined behavior if the file does not exist or cannot be open for read+update mode.
while (!feof(pFile)) does not stop exactly at the end of file because the end of file indicator returned by feof() is only set when a read operation fails, not before. You should instead write:
while (fgets(buf, 68, pFile) != NULL) {
if the file has lines longer than 66 characters, the line numbers will be computed incorrectly.
There are 2 ways to replace the text in the file:
you can create a temporary file and write the modified contents to it. Once the contents have all been converted, delete the original file with remove() and rename the temporary file to the original name with rename(). This method uses extra space on the storage device, and requires that you can create a new file and determine a file name that does not conflict with existing file names.
alternately, you can read the complete contents of the original file and overwrite it with the modified contents from the start. This works because the modified contents is longer than the original contents. This method may fail if the file is very large and does not fit in memory, which is rather rare today for regular text files.
Here is a modified version using the second approach:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE *pFile;
int c, line, changes;
unsigned char *buf;
size_t pos, length, size;
char replacement[] = "heet";
/* open the file */
pFile = fopen("myfile.txt", "r+");
if (pFile == NULL) {
printf("cannot open myfile.txt\n");
return 1;
}
/* read the file */
buf = NULL;
length = size = 0;
while ((c = getc(pFile)) != EOF) {
if (length == size) {
size = size + size / 2 + 128;
buf = realloc(buf, size);
if (buf == NULL) {
printf("not enough memory to read myfile.txt\n");
fclose(pFile);
return 1;
}
}
buf[length++] = c;
}
/* write the modified contents */
rewind(pFile);
line = 1;
changes = 0;
for (pos = 0; pos < length; pos++) {
c = buf[pos];
if (c == '\n')
line++;
if (c == '#') {
if (changes++ == 0)
printf("changes are made in this lines:\t");
else
printf(", ");
printf("%d", line);
fputs(replacement, pFile);
} else {
putc(c, pFile);
}
}
free(buf);
fclose(pFile);
if (changes == 0)
printf("no changes were made\n");
else
printf("\n");
return 0;
}
To rewrite a word in file using fwrite or any file writing function, use fgetpos and fsetpos. Otherwise seeking file pointer alone will not work. Still this work, if the file pointer is end of the file, it means append is possible.
I have an issue with as assignment regarding files.
Here is the assignment:
I am asked to write a code for a program that adds to each line in a text file, the number of that line. for example if the original file was:
Hi my name is Oria
I study programming
I love dogs
I use stackoverflow
It will be changed to:
1 Hi my name is Oria
2 I study programming
3 I love dogs
4 I use stackoverflow
But I don't know how to skip a line. After I've written the first number, how do I advance the *file pointer to be the first character of the next line?
This can be done with the help of writing it into another file.
Read the each line of a input file using fgets and start the loop count, then write to output file with count and data.
#include <stdio.h>
int main()
{
FILE *src, *dest;
char buf[64];
int i = 0;
src = fopen("in.txt", "r");
dest = fopen("out.txt", "w");
while(fgets(buf, 64, src) != NULL){
i++;
fprintf(dest, "%d %s", i,buf);
}
fclose(src);
fclose(dest);
return 0;
}
Use getline(3) to read lines in a loop. Within the loop, you can skip lines at will.
while (1) {
....
getline();
if (...)
continue;
}
I want to change lines which contain the # symbol in a text file with heet using C.
I have tried it this way, but it did not work thoroughly, it just replaces the characters & overwrites not the whole string, like I want.
Is there any other trick to remove or delete a whole line from the file? So, we can easily replace it.
myfile.txt: (before execution)
Joy
#Smith
Lee
Sara#
Priyanka
#Addy
Code:
#include <stdio.h>
#include <string.h>
int main() {
FILE *pFile;
fpos_t pos1, pos2;
int line = 0;
char buf[68]
char *p;
char temp[10] = "heet";
pFile = fopen("myfile.txt", "r+");
printf("changes are made in this lines:\t");
while (!feof(pFile)) {
++line;
fgetpos(pFile, &pos1);
if (fgets(buf, 68, pFile) == NULL)
break;
fgetpos(pFile, &pos2);
p = strchr(buf, '#');
if (p != NULL) {
printf("%d, " , line);
fsetpos(pFile, &pos1);
fputs(temp, pFile);
}
fsetpos(pFile, &pos2);
}
fclose(pFile);
return 0;
}
myfile.txt: (after execution)
Joy
heetth
Lee
heet#
Priyanka
heety
Output:
changes are made in this lines: 2, 4, 6,
myfile.txt: (I want to get)
Joy
heet
Lee
heet
Priyanka
heet
The best way of doing what you want is to use a utility like sed. It is faster and uses less memory than anything you (or I) would write.
That aside, let's assume you want to go ahead and write it yourself anyway.
A file is just like a long array of bytes. If you want to increase or decrease the length of one line, it affects the position of every byte in the rest of the file. The result can be shorter (or longer) than the original. As the result can be shorter, modifying the file in place is a bad idea.
The following pseudo-code illustrates a simple approach:
open original file
open output file
allocate a line buffer that is large enough
read a line from the original file
do
return an error if the buffer is too small
manipulate the line
write the manipulated line to the output file
read a line from the original file
loop until read returns nothing
sed does it much smarter. I once saw an explanation on how sed works, but my google karma can't seem to find it.
Edit:
How to do it using sed:
sed -e 's/.*\#.*/heet/g' myfile.txt
The s, or substitute, command of sed can replace one string, or regular expression, with another string.
The above command is interpreted as:
replace any line that has a # somewhere in it with heet. The final g tells sed to do this globally, i.e. in the entire file.
Edit2:
By default, sed writes to standard output.
To rewrite the file you should redirect the output to a file and then rename it.
In linux, do the following (you can run command line stuff from C with system):
sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt
rm myfile.txt
mv temp_file123.txt myfile.txt
From C:
system("sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt");
system("rm myfile.txt");
system("mv temp_file123.txt myfile.txt");
If you want to do it with just one call to system, put all the command line stuff in a shell script.
You should probably treat input/output like a UNIX utility and replace the line by reading in the whole input and writing the whole output like sed would or something. It's going to be a pain to edit the line in place as you need to shift the following text 'down' in order to make it work.
You cannot achieve your goal by overwriting the file in place like you do in the code because heet is 3 bytes longer than # and there is no standard function to insert bytes in the middle of a file.
Note also these important issues:
you do not test if fopen() succeeds at opening the file. You have undefined behavior if the file does not exist or cannot be open for read+update mode.
while (!feof(pFile)) does not stop exactly at the end of file because the end of file indicator returned by feof() is only set when a read operation fails, not before. You should instead write:
while (fgets(buf, 68, pFile) != NULL) {
if the file has lines longer than 66 characters, the line numbers will be computed incorrectly.
There are 2 ways to replace the text in the file:
you can create a temporary file and write the modified contents to it. Once the contents have all been converted, delete the original file with remove() and rename the temporary file to the original name with rename(). This method uses extra space on the storage device, and requires that you can create a new file and determine a file name that does not conflict with existing file names.
alternately, you can read the complete contents of the original file and overwrite it with the modified contents from the start. This works because the modified contents is longer than the original contents. This method may fail if the file is very large and does not fit in memory, which is rather rare today for regular text files.
Here is a modified version using the second approach:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE *pFile;
int c, line, changes;
unsigned char *buf;
size_t pos, length, size;
char replacement[] = "heet";
/* open the file */
pFile = fopen("myfile.txt", "r+");
if (pFile == NULL) {
printf("cannot open myfile.txt\n");
return 1;
}
/* read the file */
buf = NULL;
length = size = 0;
while ((c = getc(pFile)) != EOF) {
if (length == size) {
size = size + size / 2 + 128;
buf = realloc(buf, size);
if (buf == NULL) {
printf("not enough memory to read myfile.txt\n");
fclose(pFile);
return 1;
}
}
buf[length++] = c;
}
/* write the modified contents */
rewind(pFile);
line = 1;
changes = 0;
for (pos = 0; pos < length; pos++) {
c = buf[pos];
if (c == '\n')
line++;
if (c == '#') {
if (changes++ == 0)
printf("changes are made in this lines:\t");
else
printf(", ");
printf("%d", line);
fputs(replacement, pFile);
} else {
putc(c, pFile);
}
}
free(buf);
fclose(pFile);
if (changes == 0)
printf("no changes were made\n");
else
printf("\n");
return 0;
}
To rewrite a word in file using fwrite or any file writing function, use fgetpos and fsetpos. Otherwise seeking file pointer alone will not work. Still this work, if the file pointer is end of the file, it means append is possible.