I'm writing a code where I can be given a directory of .txt files, and specific strings that appear throughout each file, and do some simple comparisons. code chunk will be posted below.
So, My task:Open directory>open file>compare strings>open next file(repeat)
Until I run out of files.
What is wrong:My code currently prints the first file name( full path name) infinitely until it crashes, nothing is printed to fp1. It is supposed to only print the file name once, but it never gets past that first file, where, obviously, I would like it to go through all the files in the directory.
I'm sorry that I'm fairly new to C so I might be unclear as to how these functions actually operate.
Please correct me if I'm wrong, I want to see if I understand correctly.
while ((in_file = readdir(FD))!= NULL){
Should basically traverse through a directory and "look" the name of each file.
I then do some very inefficient work around, which you will probably laugh at me for, and I manage to get the full path name of the first file in the directory.
I then assign that path name to entry_file pointer, where it gets opened by fgets().
I believe fgets() should read each line individually until it sees a EOF character
Now, I had this section working before I added the directory stuff, where I was just opening one file by using fopen() with its full path name, and I haven't touched it. So I don't think my problem is here, but nothing is being printed to fp1 at all, so I really don't know.
I then do some simple string comparisons and try to print matches to fp1
When it reaches the end of the file, it should close the file, and then go back up to readdir() and repeat the process with the next file
Thank you so much for any help. I probably sound like an idiot, but I just have no idea what could cause this.
Yes, I realize its very messy, and I have many unused and pointless variables. I've been trying to figure this out for days, trying many different methods.
int main(void)
{
char str1[10000];
char str2[] = { "Measure L1 current Tank Heater ON: Passed" };
char str3[] = { "Measure L1 current Tank Heater ON: Failed" };
char str4[] = { "Measure L1 current Manifold Heater ON: Passed" };
char str5[] = { "Measure L1 current Manifold Heater ON: Failed" };
char str6[] = { "Measure L1 current (verify heaters off) Manifold: Passed" };
char str7[] = { "Measure L1 current (verify heaters off) Manifold: Failed" };
char sn[] = { "Serial Number: 1" };
DIR* FD;
struct dirent* in_file;
int lcount = 0;//line counter
char *ret;
int linenum = 0;//temp line count
char mes[500];//measurement
double val = 0;//value
char unit[500];//units
char pathstr1[38] = ("C:/Users/liam.king/Desktop/TestFiles/");
char pathstr2[200];
DWORD retval = 0;
char buffer[BUFSIZE] = ("");
char buf[BUFSIZE] = ("");
char** lppPart = {NULL};
FILE *fp, *fp1, *filewrite;
FILE *entry_file;
//fp = fopen("C:/Users/liam.king/Desktop/TestFiles/ProBlueUnit_UpgradeRev4_Report[1022230.SA15E14082][9 39 00 AM][5 19 2015].txt", "r");
fp1 = fopen("C:/Users/liam.king/Desktop/ProBlueTestWrite.txt", "a");
filewrite = fopen("C:/Users/liam.king/Desktop/FileWrite.txt", "w+");
if (fp1 == NULL){
printf("Invalid file name");
return 0;
}
if ((FD = opendir(LONG_DIR_NAME))==NULL)
{
printf("Error: Failed to open directory\n");
return 0;
}
else{
printf("Directory opened successful\n");
}
while ((in_file = readdir(FD))!= NULL){
if (strcmp(in_file->d_name, ".") == 0 || strcmp(in_file->d_name, "..") == 0)
continue;
fprintf(filewrite, "%s", pathstr1);
fprintf(filewrite,"%s", in_file->d_name);
fclose(filewrite);
filewrite = fopen("C:/Users/liam.king/Desktop/FileWrite.txt", "r");
fscanf(filewrite, "%[^\n]%*c", pathstr2);
printf("%s\n", pathstr2);//check file name is correct
entry_file = fopen(pathstr2, "r");
fclose(filewrite);
if (entry_file != NULL){
//printf("SUCCESSFULL OPENING\n");
//fprintf(fp1, "Does this work?\n");
}
else if (entry_file == NULL){
printf("Error: Failed to open entry file\n");
return 0;
}
while (fgets(buffer, 256, entry_file) != NULL){//string being stored in str1 from file *entry_file
lcount++;
ret = strstr(str1, sn);
if (ret != NULL){
fprintf(fp1, "%s\n", str1);
}
ret = strstr(str1, str2);
if (ret != NULL){// compares str1 and 2
fprintf(fp1, "Found"" %s ""at line %d\n", str1, lcount);//if same, declare match and what line found at.
linenum = lcount;
}
//comparing more strings
}
fclose(entry_file);
}
fclose(fp1);
return 0;
}
Since pathstr2 is declared as a local array, you should use this:
while ((in_file = readdir(FD)) != NULL) {
if (!strcmp(in_file->d_name, ".") || !strcmp(in_file->d_name, ".."))
continue;
snprintf(pathstr2, sizeof(pathstr2), "%s%s", pathstr1, in_file->d_name);
entry_file = fopen(pathstr2, "r");
...
while (fgets(buffer, sizeof(buffer), entry_file) != NULL) {
lcount++;
if (strstr(buffer, sn)) {
fprintf(fp1, "%s", buffer);
}
if (strstr(buffer, str1)) {
fprintf(fp1, "Found \"%s\" at line %d\n", str1, lcount);
linenum = lcount;
}
...
}
fclose(entry_file);
}
The tests you perform with strstr on the lines read from entry_file are not incorrect. You should specify buffer instead of str1 as the first argument.
Also note that strstr searches for the second string in the whole line. If the string should be starting at the beginning of the line, you should write:
if (!strncmp(buffer, str1, strlen(str1))) {
// line starts with str1
}
Related
I have this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* ptr = fopen("data.txt","r");
char filename[100];
if (ptr==NULL)
{
printf("no such file.");
return 0;
}
char buf[100];
while (fscanf(ptr,"%*s %*s %s ",buf)==1)
printf("%s\n", buf);
printf("Create a file \n");
scanf("%s", filename);
fptr2 = fopen(filename, "w");
if (fptr2 == NULL)
{
printf("Cannot open file %s \n", filename);
exit(0);
}
c = fgetc(fptr1);
while (c != EOF)
{
fputc(c, fptr2);
c = fgetc(fptr1);
}
printf("\nContents copied to %s", filename);
fclose(fptr1);
fclose(fptr2);
return 0;
}
}
It coppies full content from one file to another. I need to copy only strings that have 5 as the last character (3 column)
For example Data.txt looks like that:
Alex 10B 4
John 10A 3
Kate 10C 5
In file that I will create during execution has to be coppied only Kate 10C 5 string. I've been trying for hours but I don't know how to do this. Can you help me?
In the end of each line there is a newline character, (\n) you can use that to read line by line and copy only the ones that you want:
FILE* dest = fopen("out.txt", "w+"); // supressed null check for simplicity
char buf[100];
char* char_to_find;
// parse line by line
while (fscanf(ptr, " %99[^\n]", buf) == 1){
char_to_find = buf;
// reach the end of the line
while(*char_to_find){
char_to_find++;
}
//move one back
char_to_find--;
// if it's 5 save, if not move on
if(*char_to_find == '5' && *(char_to_find - 1) == ' '){
fputs(buf, dest);
}
}
Live demo
The problem is that the function call
while (fscanf(ptr,"%*s %*s %s ",buf)==1)
consumes the input from the input stream, so that it is no longer available for copying. You are only saving the contents of the last field, but all other data is lost.
I suggest that you read one line at a time into a memory buffer, by calling the function fgets in a loop. That way, you will process one line of input per loop iteration, and will be saving the contents of the entire line.
In every loop iteration, you can use sscanf on this memory buffer to determine whether the third field has the desired value, and if it does, then you copy the entire line to the output file. Otherwise, you do nothing and proceed to the next line (i.e. the next loop iteration).
char line[100];
//process one line of input per loop iteration
while ( fgets( line, sizeof line, input_file ) != NULL )
{
char third_field[20];
if (
//third field was successfully extracted
sscanf( line, "%*s%*s%19s", third_field ) == 1
&&
//third field contains the string "5"
strcmp( third_field, "5" ) == 0
)
{
//copy entire line to output file
fputs( line, output_file );
}
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* ptr = fopen("data.txt","r");
char filename[100];
if (ptr==NULL)
{
printf("no such file.");
return 0;
}
printf("Create a file \n");
scanf("%s", filename);
FILE* dest = fopen(filename, "w+"); // check for null like above
char buf[100];
char* char_to_find;
while (fscanf(ptr,"%99[^\n] ", buf) == 1){
char_to_find = buf;
while(*char_to_find != 0){
char_to_find++;
}
char_to_find--;
if(*char_to_find == '5'){
printf("%s\n", buf); // test ptint
fputs(buf, dest);
}
}
}
I'm trying to get better at coding in general and C in particular, and am coding a small text adventure game. I read a string input by the user i.e LOOK room and compare it to a txt file with the list of commands for that particular section.
As I am reading from the text file I have a counter which keeps track of which line is being read, when the match is made I convert the line number to a character and concatenate it to "outside.txt" so that when the correct command is input it will read from the correct file i.e LOOK room would load text from 1outside.txt etc.
However, when inputting anything it just loops on "I dont understand" forever. Any explanation as to why or constructive comments on my code are appreciated, especially if I am misunderstanding how files and/or strings in c.
int mansionOutside(void)
{
int stop = 1;
char choice[25];
char word_match[25];
char text_line[73];
char line1[25];
char temp[2];
int counter;
FILE *fptr;
fptr = fopen("mansion_commands.txt", "r");
if (fptr == NULL)
{
printf("ERROR!");
}
else
{
while (stop == 1)
{
printf("\n");
fgets(choice, sizeof choice, stdin);
while (fgets (line1, 25, fptr)!= NULL)
{
if (strcmp(line1, choice) == 0)
{
printf("%s\n", line1);
stop = 0;
break;
}
else
{
counter++;
printf("%s + %s\n", line1, choice);
}
}
if (stop == 1)
{
printf("I dont understand\n");
counter = 1;
}
}
fclose(fptr);
counter = counter + '0';
temp[0] = counter;
temp[1] = '\0';
strncat(word_match, temp , 1);
strcat(word_match, ".txt");
fptr = fopen(word_match, "r");
if (fptr == NULL)
{
printf("ERROR!\n");
}
else
{
printf("Debugging : File opened Successfully\n");
while (fgets (text_line, 72, fptr) != NULL)
{
printf("%s", text_line);
//delay(2);
}
}
}
}
EDIT : Took in suggestions for improvements to avoid Buffer overflows such as using > fgets , but I think there is something I have missed. Now If I input anything contained in the file, it works fine. If however I input something wrong, then something correct on re-prompt, It skips the inner while loop all together and goes straight to "I don't understand".
The following is what happens when my input is LOOK room, and then LOOK mansion.
I am trying to read a file in C and then store values after a certain word is read. For example, in my input.txt file, the following are the contents:
GREETINGS
Hello 13
Namaste 24
Hola 36
FLAVORS
Vanilla 23
Chocolate 78
I want to read past GREETINGS and then store Hello and its value 13 then Namaste and its value 24, etc. And then read past FLAVORS and store Vanilla and its value 23, etc. And so on...
I know how to open a file but not sure how to proceed from there.
void readInput() {
char input_file[100];
FILE *fp;
printf("Please enter the name of the file you would like to read: \n");
scanf("%s", input_file);
printf("You entered: %s\n", input_file);
fp = fopen(input_file, "r");
if (fp == NULL) {
printf("File does not exist.\n");
exit(1);
}
else
printf("This file exists!\n");
}
From your sample data it is not clear whether the lines with data have the always the same format. So I
suggest that you store in a variable the current mode (that means GREETINGS, FLAVOR, etc) and you call
a specific parsing function for every mode depending of the value of the current
mode.
I'd create this enum first
typedef enum {
MODE_GREETINGS = 0, // <-- important that this value is 0
MODE_FLAVORS,
...
MODE_INVALID
} Modes;
and a variable (this can be a global variable) with all modes:
const char *modes_lookup[] = {
"GREETINGS",
"FLAVORS",
...
};
Then I'd write a function that returns the mode:
Modes get_mode(const char *src)
{
if(src == NULL)
return MODE_INVALID;
for(size_t i = 0; i < sizeof modes_lookup / sizeof modes_lookup[0]; ++i)
{
if(strcmp(src, modes_lookup[i]) == 0)
return i;
}
return MODE_INVALID;
}
Now you can parse the file like this:
char line[1024];
Modes mode = MODE_INVALID;
size_t lineno = 0;
while(fgets(line, sizeof line, fp))
{
lineno++;
// removing newline
line[strcspn(line, "\n")] = 0;
Modes newmode = get_mode(line);
// check if line is a GREETINGS, FLAVOR, etc line
if(newmode != MODE_INVALID)
{
// sets the new mode and continue with the next line
mode = newmode;
continue;
}
// parsing depending on the current mode
if(mode == MODE_GREETINGS)
{
if(parse_greetings(line) == 0)
{
fprintf(stderr, "Cannot parse data on line %zu\n", lineno);
break;
}
continue;
}
if(mode == MODE_FLAVORS) {
if(parse_flavor(line) == 0)
{
fprintf(stderr, "Cannot parse data on line %zu\n", lineno);
break;
}
continue;
}
// more (if mode == MODE_xxx) cases as needed
if(mode == MODE_INVALID)
{
// mode == MODE_INVALID
fprintf(stderr, "File does not start with a mode line.\n");
break;
}
}
Then you've got to write the parse_greetings, parse_flavor, parse_xxx functions. Like I said
before, it's not clear from your sample whether the format will be always the
same, so it depends on the format whether you use strtok or sscanf. Also
your description of how and where you want to store the values is very vague, so
I don't know what would be the best for your.
The easiest would be sscanf and if the data line gets more complex, you can then
use strtok.
For example with sscanf
int parse_greetings(const char *line)
{
if(line == NULL)
return 0;
char name[20];
int val;
if(sscanf(line, "%19s %d", name, val) != 2)
return 0;
// do whatever you need with 'name' and 'val'
return 1;
}
And with strtok:
int parse_greetings(char *line)
{
if(line == NULL)
return 0;
char name[20];
int val;
const char *delim = " \t\r\n";
char *token = strtok(line, NULL);
// line has only delimiters
if(token == NULL)
return 0;
strncpy(name, token, sizeof name / sizeof name[0]);
name[(sizeof name / sizeof name[0]) - 1] = 0;
token = strtok(NULL, delim);
if(token == NULL)
return 0;
char *end;
val = strtol(token, &end, 0);
// check if token is a number
if(*end != '\0')
return 0;
// do whatever you need with 'name' and 'val'
return 1;
}
I'm not sure what exact criteria you're using to choose which lines to skip, but the next step for reading lines is to use fscanf or fgets. This tutorial should help you get started with reading files in C.
Edit, to make this more relevant after your comment:
fgets may be a better choice. You'll need to read each line, then loop through each character, to check if they are all uppercase.
If they are not uppercase, you can use fscanf, using the format %s %d, to scan the data line.
I want to check if there are any duplicates in a .txt file. I've wrote a code but it's not running. I'm not sure about opening the norep.txt file in "a+" mode. The idea is to put the first word of my text in the norep.txt file, then compare every word in the text.txt with the words in norep.txt and copy only the words I need in the file.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fd;
FILE *ft;
char aux[30];
char aux1[30];
int len;
fd = fopen("c:\\text.txt", "r");
if (fd == NULL) {
puts("Error");
}
ft = fopen("c:\\norep.txt", "a+");
if (ft == NULL) {
puts("Error");
}
fscanf(fd, "%s", aux);
fprintf(ft, "%s", aux);
rewind(fd);
rewind(ft);
while (!feof(fd)) {
fscanf(fd, "%s", aux);
while (!feof(ft)) {
fscanf(ft, "%s", aux1);
len = strcmp(aux, aux1);
if (len != 0) {
fprintf(ft, "%s", aux);
}
}
rewind(ft);
}
return 0;
}
You should flush the output file before you rewind it.
fflush - flush a stream or fflush
Of course, this will not fix your problem because:
Note below that the manual says that reposition operations are ignored so that your attempt to read will always find the end of file.
append: Open file for output at the end of a file. Output operations
always write data at the end of the file, expanding it. Repositioning
operations (fseek, fsetpos, rewind) are ignored. The file is created
if it does not exist.
What you should probably do is create an internal memory table that keeps all the unique entries and write it out to a new file after all processing is done. As you read the fd file, check the list and add a new entry if it is not already in the list. Then after you have finished processing fd, then and only then write out your list. Of course, this may be too big depending on the size of your data file.
You could append each unique entry to the output file as you go. but you would need to have some method of checking the previous entries without trying to read the output file.
The usual way to go about this is to read the input file word for word, store the necessary information in some way and then, after you have read all information from the file, write the desired output to the output file.
A rough skeleton of that approach might look like this:
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in;
FILE *out;
char word[30];
// (1) Read all words
in = fopen(infile, "r"); // .. and enforce success
while (fscanf(in, "%29s", word) == 1) {
// store word somewhere
}
fclose(in);
// (2) Determine unique words somehow
// (3) Write out unique words
out = fopen(outfile, "w"); // .. and enforce success
for (i = 0; i < nunique; i++) {
fprintf(out, "%s\n", unique[i]);
}
fclose(out);
return 0;
}
The actual algorithm to fin the unique words is missing from this incomplete skeleton code.
If you really want to test the words in a file for uniqueness without using additional memory beyond the current word, you can open the input file twice, with independent file pointers. Then you can write a loop like so:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in1;
FILE *in2;
FILE *out;
char word1[30];
char word2[30];
in1 = fopen(infile, "r");
in2 = fopen(infile, "r");
out = fopen(outfile, "w");
if (in1 == NULL || in2 == NULL || out == NULL) {
fprintf(stderr, "Could not open all required files.\n");
exit(1);
}
while (fscanf(in1, "%29s", word1) == 1) {
int count = 0;
while (fscanf(in2, "%29s", word2) == 1) {
if (strcmp(word1, word2) == 0) count++;
if (count > 1) break;
}
if (count == 1) fprintf(out, "%s\n", word1);
rewind(in2);
}
fclose(in1);
fclose(in2);
fclose(out);
return 0;
}
This will, of course, re-read the file as often as there are words in the file. Not a good approach to find the unique words in Moby-Dick. I recommend that you look into the memory-based approach.
I want to read a text file line by line, perform some checks, and if the line is not required, delete it.
I have done the code for reading line, but I don't know how to delete that line if it is not required by me.
Please help me find the simplest method for deleting the line.
Here is my code snippet what I tried:
char ip[32];
int port;
DWORD dwWritten;
FILE *fpOriginal, *fpOutput;
HANDLE hFile,tempFile;
hFile=CreateFile("Hell.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
tempFile=CreateFile("temp.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(hFile,"10.0.1.25 524192\r\n\r\n10.0.1.25 524193\r\n\r\n",strlen("10.0.1.25 524192\r\n\r\n10.0.1.25 524193\r\n\r\n"),&dwWritten,0);
fpOriginal = fopen("Hell.txt", "r+");
fpOutput = fopen("temp.txt", "w+");
while (fscanf(fpOriginal, " %s %d", ip, &port) > 0)
{
printf("\nLine1:");
printf("ip: %s, port: %d", ip, port);
char portbuff[32], space[]=" ";
sprintf(portbuff, "%i",port);
strcat(ip," ");
strcat(ip,portbuff);
if(port == 524192)
printf("\n Delete this Line now");
else
WriteFile(tempFile,ip,strlen(ip),&dwWritten,0);
}
fclose(fpOriginal);
fclose(fpOutput);
CloseHandle(hFile);
CloseHandle(tempFile);
remove("Hell.txt");
if(!(rename("temp.txt","Bye.txt")))
{
printf("\ncould not rename\n");
}
else
printf("\nRename Done\n");
//remove ("Hell.txt");
here's an example:
char* inFileName = "test.txt";
char* outFileName = "tmp.txt";
FILE* inFile = fopen(inFileName, "r");
FILE* outFile = fopen(outFileName, "w+");
char line [1024]; // maybe you have to user better value here
int lineCount = 0;
if( inFile == NULL )
{
printf("Open Error");
}
while( fgets(line, sizeof(line), inFile) != NULL )
{
if( ( lineCount % 2 ) != 0 )
{
fprintf(outFile, "%s", line);
}
lineCount++;
}
fclose(inFile);
fclose(outFile);
// possible you have to remove old file here before
if( !rename(inFileName, outFileName) )
{
printf("Rename Error");
}
You can copy all line wich does not contain the number 2 into a new file and then use the new file instead the old file
fp = fopen("File.txt", "r");
fp2 = fopen("File_copy.txt", "w");
while (fscanf(fp, " %s %d", string, &number) > 0) {
if(number != 2)
{
fprintf(fp2, "%s %d\n", string, number);
}
}
close(fp);
close(fp2);
remove("File.txt");
rename( "File_copy.txt", "File.txt" );
Another solution could be to write back to the same file (write back what you read out except for the lines you don't want) and use the Windows API function SetEndOfFile to truncate it when finished. This will probably be a bit messier to code but you won't need to create a second copy of the file so it's more efficient from a disk usage standpoint.
There are many to solve this problem one of them is, you can open another file for writing when you reach at a point where you don't want to write omit that paint and continue writing until end of file. Latterly you can delete old file and rename new file with old one.
if(number == 2)
{
continue;
}
else
{
writetofilefunction()
}