int main()
{
int i;
FILE *list,*file;
char temp[30];
list=fopen("filelist","rb");
while(fgets(temp,30,list)!=NULL)
{
file=fopen(temp,"r");
{
fclose(list);
return 0;
}
This is my code I basically want to open all files in filelist but my fopen call (exept the first one always returns a NULL am i missing something also this is my filelist
file1
file2
file3
file4
also i dont use file extensions and files exist in the same directory wtih executable.
fgets() stores the new-line character into the buffer it is populating so you need to remove it before calling fopen() within the while.
From the linked reference page for fgets():
Reads at most count - 1 characters from the given file stream and stores them in str. The produced character string is always NULL-terminated. Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character.
Example code to remove the new-line:
char* nl = strrchr(temp, '\n');
if (nl) *nl = 0;
fgets leaves the newline on the end of the string, which you can plainly see if you add the following line afterwards:
printf ("[%s]\n", temp);
You'll see something like:
[file1
]
You need to remove it before use, which you can do this with something like:
size_t sz = strlen (temp);
if (sz > 0)
if (temp[sz-1] == '\n')
temp[sz-1] = '\0';
You can see this effect in action in the following complete program:
#include <stdio.h>
#include <string.h>
int main (void) {
size_t sz;
char temp[30];
printf ("\n> ");
while (fgets (temp, sizeof(temp), stdin) != NULL) {
printf ("before: [%s]\n", temp);
sz = strlen (temp);
if (sz > 0) {
if (temp[sz-1] == '\n') {
temp[sz-1] = '\0';
}
}
printf ("after : [%s]\n", temp);
printf ("\n> ");
}
return 0;
}
It basically uses your exact method to get a line using fgets (but from standard input) and then outputs the result both before and after removal of the trailing newline. A sample run follows:
pax> ./testprog
> hello
before: [hello
]
after : [hello]
> goodbye
before: [goodbye
]
after : [goodbye]
> [CTRL-D]
pax> _
You may also want to look at a few other things in that code segment:
the use of an open brace { at the end of the while loop.
the fact that you're opening the files within the loop and not doing anything with them (including closing them).
the use of "rb" open mode. Usually this is unnecessary, it's certainly unnecessary if you know it's a text file.
you should always check the return codes of functions that can fail (like fopen) before using them.
the canonical form of main in C where no arguments are needed is int main (void).
I'll state my case of which I am still uncertain: I thought my problem was with "fopen", but after trying every single solution, I ran into the extension problem, which I'm facing in Windows 10. It appears that Windows puts ".txt" automatically but, if you put ".txt" as extension, the name becomes ".txt.txt" at the end. So I left the file name with no extension, and put "file.txt" as argument of "fopen", and that was the only way it has worked for me.
Related
Today I decided to learn to code for the first time in my life. I decided to learn C. I have created a small program that checks a txt file for a specific value. If it finds that value then it will tell you that that specific value has been found.
What I would like to do is that I can put multiple files go through this program. I want this program to be able to scan all files in a folder for a specific string and display what files contain that string (basically a file index)
I just started today and I'm 15 years old so I don't know if my assumptions are correct on how this can be done and I'm sorry if it may sound stupid but I have been thinking of maybe creating a thread for every directory I put into this program and each thread individually runs that code on the single file and then it displays all the directories in which the string can be found.
I have been looking into threading but I don't quite understand it. Here's the working code for one file at a time. Does anyone know how to make this work as I want it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//searches for this string in a txt file
char searchforthis[200];
//file name to display at output
char ch, file_name[200];
FILE *fp;
//Asks for full directory of txt file (example: C:\users\...) and reads that file.
//fp is content of file
printf("Enter name of a file you wish to check:\n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//If there's no data inside the file it displays following error message
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
//asks for string (what has to be searched)
printf("Enter what you want to search: \n");
scanf("%s", searchforthis);
char* p;
// Find first occurrence of searchforthis in fp
p = strstr(searchforthis, fp);
// Prints the result
if (p) {
printf("This Value was found in following file:\n%s", file_name);
} else
printf("This Value has not been found.\n");
fclose(fp);
return 0;
}
This line,
p = strstr(searchforthis, fp);
is wrong. strstr() is defined as, char *strstr(const char *haystack, const char *needle), no file pointers in it.
Forget about gets(), its prone to overflow, reference, Why is the gets function so dangerous that it should not be used?.
Your scanf("%s",...) is equally dangerous to using gets() as you don't limit the character to be read. Instead, you could re-format it as,
scanf("%199s", searchforthis); /* 199 characters + \0 to mark the end of the string */
Also check the return value of scanf() , in case an input error occurs, final code should look like this,
if (scanf("%199s", searchforthis) != 1)
{
exit(EXIT_FAILURE);
}
It is even better, if you use fgets() for this, though keep in mind that fgets() will also save the newline character in the buffer, you are going to have to strip it manually.
To actually perform checks on the file, you have to read the file line by line, by using a function like, fgets() or fscanf(), or POSIX getline() and then use strstr() on each line to determine if you have a match or not, something like this should work,
char *p;
char buff[500];
int flag = 0, lines = 1;
while (fgets(buff, sizeof(buff), fp) != NULL)
{
size_t len = strlen(buff); /* get the length of the string */
if (len > 0 && buff[len - 1] == '\n') /* check if the last character is the newline character */
{
buff[len - 1] = '\0'; /* place \0 in the place of \n */
}
p = strstr(buff, searchforthis);
if (p != NULL)
{
/* match - set flag to 1 */
flag = 1;
break;
}
}
if (flag == 0)
{
printf("This Value has not been found.\n");
}
else
{
printf("This Value was found in following file:\n%s", file_name);
}
flag is used to determine whether or not searchforthis exists in the file.
Side note, if the line contains more than 499 characters, you will need a larger buffer, or a different function, consider getline() for that case, or even a custom one reading character by character.
If you want to do this for multiple files, you have to place the whole process in a loop. For example,
for (int i = 0; i < 5; i++) /* this will execute 5 times */
{
printf("Enter name of a file you wish to check:\n");
...
}
Here's the file I want to read.
single
splash
single
V-Line
h-line
Macro for checking if string is equal.
#define STR_MATCH(a,b) (strncmp((a),(b),strlen(b)+1) == 0)
Here's what i'm using to read it.
void readMissilesFile(char* fileName)
{
FILE* mFile;
char missile[7];
/* Open the file. */
mFile = fopen(fileName, "r");
if (mFile != NULL)
{
while (!feof(mFile))
{
fgets(missile, 7, mFile);
if (!(STR_MATCH(missile, "\n")))
{
printf("Missile: %s", missile);
}
}
fclose(mFile);
}
else
{
perror("Could not open the file.");
}
}
So i'm having difficulties as its printing out spaces when I read the line. I tried to ignore this by ensuring it only reads 7 characters which is the max length of each missile. Then I made a macro called strcmp which just checks if they are equal(to hopefully not print it).
Please find the macro attached as well.
Thanks in advance and any help is great. :)
If I understand your question correctly you can replace the newline characters by using strcspn.
You should not use feof like this, this post explains why. A safe way to read the file till the end is to use fgets as stop condition in the while loop.
The container, missile should be one char bigger than the max size of the largest string to accomodate for '\0'.
Live sample
#include <string.h>
//...
char missile[10];
//...
if (mFile != NULL)
{
while (fgets(missile, 10, mFile)) //will read till there are no more lines
{
missile[strcspn(missile, "\r\n")] = '\0'; //remove newline characters
printf("Missile: %s ", missile);
}
}
//...
I would advise the reading of this post which has detailed info about fgets, namely the issue of newline characters consumption.
There is getline function in stdio.h which reads line until delimiter. Its a POSIX though, so if you are on Windows you may lack it.
Here is example implementation:
https://github.com/ivanrad/getline/blob/master/getline.c
i need to remove the whole line containing the string a user
inserted,i'm having a hard time figuring out how i can delete this
line here's is what i tied so far.
for example if u.txt contains:
1 hello world
2 where are you
* user input: you*
u.txt now contains
1.hello world
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *tr1, *tr2;
char *p;
char chr;
char scanner [10];
int t = 1;
int sc;
tr1 = fopen("u.txt", "r");
chr = getc(tr1);
while (chr != EOF)
{
printf("%c", chr);
chr = getc(tr1);
}
printf("input your word to search:");
scanf("%s",scanner);
rewind(tr1);
tr2 = fopen("replica.txt", "w");
chr = 'A';
while (chr != EOF)
{
//expect the line to be deleted
sc= strstr(chr,scanner);
if (!sc)
{
//copy all lines in file replica.txt
putc(chr, tr2);
}
fclose(tr1);
fclose(tr2);
remove("u.txt");
rename("replica.txt", "u.txt");
tr1 = fopen("u.txt", "r");
chr = getc(tr1);
while (chr != EOF)
{
printf("%c", chr);
chr = getc(tr1);
}
fclose(tr1);
return 0;
}
You are making things difficult on yourself by using character-oriented input with fgetc() with operations that call for line-oriented input and output. Moreover, in your approach, you would delete every line in the file containing words where you is a lesser-included substring like:
"you", "your", "you're", "yourself", "you've", etc...
For a simplistic way of ensuring your don't remove lines unless they contain the word "you", you can simply check to ensure the character before and after the word is whitespace. You can use the isspace() macro provided in ctype.h to simplify the checks.
When you are faced with a line-oriented problem use line-oriented input and output functions, such as fgets() or POSIX getline() for input and puts() or fputs() for output. The only additional caveat is that line-oriented input functions read and include the trailing '\n' in the buffers they fill. Just remove where necessary by overwriting the trailing '\n' with the nul-terminating character '\0' (or simply 0).
Using a line-oriented approach will greatly simplify your task and provide a convenient way write the lines you keep to your output file in a single call rather than looping character-by-character. Using a character-oriented approach is not wrong, and it's not inherently slower than a line-oriented approach -- it's just less convenient. Match the tool to the job.
The following example reads "u.txt" and writes "v.txt" with the unwanted lines removed while preserving lines where the word is a lesser-included substring of the word being sought. (the rename() and remove() are left to you as there is nothing wrong with that part of your existing code)
Simply using a fixed buffer of sufficient size is the easiest way to do line-oriented input. You will generally know what the largest anticipated line is, just use a buffer that is more than sufficient to handle it (don't skimp!). Most lines are no more than 80-120 characters long. A fixed array of 1024-characters is more than sufficient. Just declare an array to use as a buffer to hold each line read, e.g.:
#define MAXW 32 /* max chars in word to find */
#define MAXC 1024 /* max chars for input buffer */
int main (int argc, char **argv) {
char buf[MAXC], /* buffer to hold each line */
word[MAXW]; /* user input to find/delete line */
size_t wordlen = 0; /* length of user input */
FILE *ifp, *ofp; /* infile & outfile pointers */
You can validate that sufficient arguments were provided on the command line for the input and output filenames and then open and validate each of your files, e.g.
if (argc < 3) { /* validate at least 2 program arguments given */
printf ("usage: %s infile outfile\n", strrchr (argv[0], '/') + 1);
return 1;
}
if (!(ifp = fopen (argv[1], "r"))) { /* open/validate open for reading */
perror ("fopen-ifp");
return 1;
}
if (!(ofp = fopen (argv[2], "w"))) { /* open/validate open for writing */
perror ("fopen-ofp");
return 1;
}
Now just take the input from the user and remove the trailing '\n'. Using strcspn you can get both the length of the user-input while overwriting the trailing '\n' in a single call. See: man 3 strspn, e.g.
fputs ("enter word to find: ", stdout); /* prompt for input */
fflush (stdout); /* optional (but recommended) */
if (!fgets (word, MAXW, stdin)) { /* read/validate word to find */
fputs ("(user canceled input)\n", stdout);
return 1;
}
/* get wordlen, trim trailing \n from find */
word[(wordlen = strcspn (word, "\n"))] = 0;
Now simply read a line-at-a-time and search for word within the line and validate is it a whole word and not a part of a larger word. Write all lines that don't contain word alone to your output file:
while (fgets (buf, MAXC, ifp)) { /* read each line */
char *p = strstr (buf, word); /* search for word */
if (!p || /* word not in line */
(p != buf && !isspace (*(p - 1))) || /* text before */
(!isspace (p[wordlen]) && p[wordlen] != 0)) /* text after */
fputs (buf, ofp); /* write line to output file */
}
(note: the isspace() macro from checking whether a character is whitespace is provided in the header ctype.h)
Close both files and aside from your remove() and rename() you are done. But, note you should always validate fclose() after a write to ensure you catch any errors associated with flushing the file stream on close that would not otherwise be caught by validating each write individually, e.g.
if (fclose (ofp) == EOF) { /* validate EVERY close-after-write */
perror ("fclose-ofp");
remove (argv[2]);
}
fclose (ifp); /* close input file */
}
Add the required header files and you have a working example. You can put the example to use as follows:
Example Input File
$ cat dat/u.txt
hello world
how are you
show yourself
you're missing
Example Use
$ ./bin/filermline dat/u.txt dat/v.txt
enter word to find: you
Resulting Output File
$ cat dat/v.txt
hello world
show yourself
you're missing
Look things over and compare the line-oriented approach to your use of the character-oriented use of fgetc(). Let me know if you have further questions.
You're not giving any value to chr, it is always A at least for the first loop. Is there any lines of code missed? I suggest you checking every line until you find an EOL saving it in a string. Then call strstr() with it and if the result is NULL you simply copy it into another file.
If keeping it in the same file is necessary it Will be more dificult, because you got to save a pointer to the start of each line. If this line youre studying is actually one that has to be erased, you got to recopy each following line from this pointer. It is way harder this way.
Good luck!
PS: Maybe this can help, not sure: How do I delete a specific line from text file in C?
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 know this is a dumb question, but how would I load data from a multiline text file?
while (!feof(in)) {
fscanf(in,"%s %s %s \n",string1,string2,string3);
}
^^This is how I load data from a single line, and it works fine. I just have no clue how to load the same data from the second and third lines.
Again, I realize this is probably a dumb question.
Edit: Problem not solved. I have no idea how to read text from a file that's not on the first line. How would I do this? Sorry for the stupid question.
Try something like:
/edited/
char line[512]; // or however large you think these lines will be
in = fopen ("multilinefile.txt", "rt"); /* open the file for reading */
/* "rt" means open the file for reading text */
int cur_line = 0;
while(fgets(line, 512, in) != NULL) {
if (cur_line == 2) { // 3rd line
/* get a line, up to 512 chars from in. done if NULL */
sscanf (line, "%s %s %s \n",string1,string2,string3);
// now you should store or manipulate those strings
break;
}
cur_line++;
}
fclose(in); /* close the file */
or maybe even...
char line[512];
in = fopen ("multilinefile.txt", "rt"); /* open the file for reading */
fgets(line, 512, in); // throw out line one
fgets(line, 512, in); // on line 2
sscanf (line, "%s %s %s \n",string1,string2,string3); // line 2 is loaded into 'line'
// do stuff with line 2
fgets(line, 512, in); // on line 3
sscanf (line, "%s %s %s \n",string1,string2,string3); // line 3 is loaded into 'line'
// do stuff with line 3
fclose(in); // close file
Putting \n in a scanf format string has no different effect from a space. You should use fgets to get the line, then sscanf on the string itself.
This also allows for easier error recovery. If it were just a matter of matching the newline, you could use "%*[ \t]%*1[\n]" instead of " \n" at the end of the string. You should probably use %*[ \t] in place of all your spaces in that case, and check the return value from fscanf. Using fscanf directly on input is very difficult to get right (what happens if there are four words on a line? what happens if there are only two?) and I would recommend the fgets/sscanf solution.
Also, as Delan Azabani mentioned... it's not clear from this fragment whether you're not already doing so, but you have to either define space [e.g. in a large array or some dynamic structure with malloc] to store the entire dataset, or do all your processing inside the loop.
You should also be specifying how much space is available for each string in the format specifier. %s by itself in scanf is always a bug and may be a security vulnerability.
First off, you don't use feof() like that...it shows a probable Pascal background, either in your past or in your teacher's past.
For reading lines, you are best off using either POSIX 2008 (Linux) getline() or standard C fgets(). Either way, you try reading the line with the function, and stop when it indicates EOF:
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
...use the line of data in buffer...
}
char *bufptr = 0;
size_t buflen = 0;
while (getline(&bufptr, &buflen, fp) != -1)
{
...use the line of data in bufptr...
}
free(bufptr);
To read multiple lines, you need to decide whether you need previous lines available as well. If not, a single string (character array) will do. If you need the previous lines, then you need to read into an array, possibly an array of dynamically allocated pointers.
Every time you call fscanf, it reads more values. The problem you have right now is that you're re-reading each line into the same variables, so in the end, the three variables have the last line's values. Try creating an array or other structure that can hold all the values you need.
The best way to do this is to use a two dimensional array and and just write each line into each element of the array. Here is an example reading from a .txt file of the poem Ozymandias:
int main() {
char line[15][255];
FILE * fpointer = fopen("ozymandias.txt", "rt");
for (int a = 0; a < 15; a++) {
fgets(line[a], 255, fpointer);
}
for (int b = 0; b < 15; b++) {
printf("%s", line[b]);
}
return 0;
This produces the poem output. Notice that the poem is 14 lines long, it is more difficult to print out a file whose length you do not know because reading a blank line will produce the output "x�oA". Another issue is if you check if the next line is null by writing
while (fgets(....) != NULL)) {
each line will be skipped. You could try going back a line each time to solve this but i think this solution is fine for all intents.
I have an even EASIER solution with no confusing snippets of puzzling methods (no offense to the above stated) here it is:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line;//read the line
ifstream myfile ("MainMenu.txt"); // make sure to put this inside the project folder with all your .h and .cpp files
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
Happy coding