read file

closed account (4wpL6Up4)
Hi,
I am writing a function that reads the text file “smslog_eng.txt”
and creates a new file containing all posts coming from the phone
number 0702-235689. The new file shall have the same format as the original file. Also write
a main program that uses this function. The senderFilter function is required to have
prototype as specified below:
bool senderFilter(char *logFileName, char *resultFileName, const char *sender);
Argument: logFileName – a string containing the name of the file with the SMS log
resultFileName – a string with the name of the file to be created
sender – a string containing the phone number that is to be filtered out
Return value: True – if all went well when creating the file
False – if something went wrong when creating the file.


I have to admit that I am a bit lost.
I gave the code a try but it looks like I made a mess.

Help/hints are appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  #include "pch.h"
#include <iostream>
#include<fstream>

using namespace std;

bool senderFilter(char *logFileName, char *resultFileName, const char *sender)
{
	const char sender = 0702-235689;
	int x = 0;
	ifstream input("smslog_eng.txt");
	if (!input)
	{
		cerr << "File 'smslog_eng.dat' does not open!\n";
		exit(1);
	}
	char data;
	while (input)
	{
		if (!input.get(data)) break;
		cout << data;

		if (data = sender)
		{
			x++;
		}
	}

	cout << "records with 0702 - 235689" << x << '\n';


	ofstream outfile;
	outfile.open("0702.txt");
	if (!outfile)
	{
		cerr << "File '0702.txt' couldn't open!\n";
		exit(1);
	}

	input.clear();
	input.seekg(0);
	while (input)
	{
		if (!input.get(data)) break;
		if (data = sender)
		{
			outfile << data;
		}
	}
	outfile.close();

}
Last edited on
Hello nypran,

The things that jump out at first or that I do not see are:

The function returns a "bool", but no where in the function do you return anything.

The third parameter of the function defines "sender" then on line 9 you are trying to redefine "sender" as a single "char". This will not work.

Opening and checking the file is done correctly. You even used "exit(1)" except it is wrong. It should be returning "false" at this point. The same applies for the output file.

The second if statement in the while loop is trying to set the single character "data" to what is a "char*" to a string. I think what you want is "==" to compare where "=" is to assign.

At this point I am thinking you might need the header file "cstring", but if you read the input file one character at a time you will never have enough to compare to a string.

Just before the while loop of the output section you clear the state bits and reset the file pointer to the beginning. But the second if statement has the same problem as explained above.

With out the input file and the "main" function it is difficult to guess at how you should be reading the file. Right now I am thinking you will need some more variables to read the input file and break it up into its individual fields to work with. Then when you write to the output file you can use these variables to write in the same format as the input file.

Lastly if everything worked correctly you need to return "true".

Hope that helps,

Andy
closed account (4wpL6Up4)
I have changed the outcomes to false, and changed = to ==,
however is still full of mistakes.
I am not sure what you mean by adding some variables reading the input file,
as I am reading the file the same way as the previous task, and there was no need of extra variables.
Perhaps you can give me an example ?

Here is my new code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "pch.h"
#include <iostream>
#include<fstream>
#include<cstring>

using namespace std;

bool senderFilter(char *logFileName, char *resultFileName, const char *sender)
{
	const char sender = 0702-235689;
	int x = 0;
	ifstream input("smslog_eng.txt");
	if (!input)
	{
		cerr << "File 'smslog_eng.dat' does not open!\n";
		false;
	}
	char data;
	while (input)
	{
		if (!input.get(data)) break;
		cout << data;

		if (data == sender)
		{
			x++;
		}
	}

	cout << "records with 0702 - 235689" << x << '\n';


	ofstream outfile;
	outfile.open("0702.txt");
	if (!outfile)
	{
		cerr << "File '0702.txt' couldn't open!\n";
		false;
	}

	input.clear();
	input.seekg(0);
	while (input)
	{ 
		
		if (!input.get(data)) break;
		if (data == sender)
		{
			outfile << data;
		}
	}
	outfile.close();

}

	
Last edited on
Hello nypram, I reworked your code in such a manner that it compiles and run. Also, I added exception handling.

Because I have no input files, I cannot test if the program works. But I hope, you will have a good starting point with that code for researching all unknown stuff on your own :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//  #include "pch.h"
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <cctype>

using namespace std;

bool senderFilter(
        const char *logFileName
      , const char *resultFileName
      , const char *sender
)
{
	int x = 0;
	ifstream input( logFileName );
	if (!input)
	{
	        throw runtime_error( string("File '") 
	            + logFileName +"' couldn't opened!\n");
	}
	
	// Tries to find all file positions (begin and end)
	// of all numbers related to sender.
	//
	vector< int> filePositions;
	char data;
	while (input.get(data))
	{
	        if (isdigit(data)) 
	        {
	            input.unget();
		    filePositions.push_back(input.tellg());
	        }
	        else  { continue; }
	        
	        // This part may be need customized, according to the
	        // formatting of your file content
	        string tmp;
		input >> tmp;
		
		

		if (tmp == string(sender))
		{
			x++;
			filePositions.push_back(
			    static_cast<int>(input.tellg()) 
			    - static_cast<int>(tmp.size() )
			);
		}
		else { filePositions.pop_back(); }
	}
	filePositions.push_back( input.tellg() ); // end of file

	cout << "records with " << sender << ": " << x << '\n';


	ofstream outfile( resultFileName );
	if (!outfile)
	{
	        throw runtime_error(string("File '") 
	         + resultFileName +"' couldn't opened!\n");
	}

	// Puts all stuff, related to the positions of
	// the file positions, to the output file.
	//
	input.clear();
	for (int ctr = 0;  ctr < filePositions.size();  ctr += 2)
	{
	        input.seekg(filePositions[ctr]);
	        do {
	                input.get(data);
	                outfile.put(data);
	        }
	        while (input.tellg() < filePositions[ctr+1] );
	}
	
	return true;
	
	// At end of scope file-streams get automatically closed :)
}

int main()
{
    try {
        senderFilter( "smslog_en.txt", "0702.txt", "0702-235689");
    }
    catch( runtime_error & e)
    {
        cerr << e.what();
        exit(1);
    }
}
Hello nypran,

I am reading the file the same way as the previous task
Just because this worked in the previous program does not mean that it will work here.

Twice it has been mentioned to post the input file and nothing.

Without knowing what you are working with there is no way to tell what is wrong. Trying to read one character at a time and compare it to a may character string will not work.


FirstName LastName address phoneNumber anythingElse


This is concidered a record and each piece is considered a field. When reading this file each field would most likely be read into a string (either a char array or a std::string).

I pointed out the difference between "=" and "==", but you can not use this to compare two "char" arrays. This would work with a "std::string", but the "char" array would need the function "strcmp()" or one of the other functions, This will depend on what your compiler will allow.

This is why you would need other variables to hold each field in the input file.

Until you can read and process the input file there is no point on working on the output file until you have something to work with. Also it may be easier to work with the output file while reading the input file.

nuderobmonkey has a nice solution, but I feel that there is a lot of that code that you are not ready for yet. It would still be a good idea to save his code for future use.

Based on your instructions I will see what I can come up with although without your input file mine could be different.

Hope that helps,

Andy
nypran, looking at your original post, I see a mistake that beginners commonly make.

In programming, you have to be very precise. That means following the instructions of the assignment to the letter. Usually the professor has carefully worded the assignment and every word matters. Let's look at the first few lines of your function:

1
2
bool senderFilter(char *logFileName, char *resultFileName, const char *sender)
{
So far so good. You've declared it exactly as asked.
const char sender = 0702-235689; That's wrong. The sender is specified in the parameter called sender above.
1
2
	int x = 0;
	ifstream input("smslog_eng.txt");
That's wrong. The input file is specified in the logFileName parameter.
1
2
3
4
5
if (!input)
	{
		cerr << "File 'smslog_eng.dat' does not open!\n";
		exit(1);
	}
The instructions say that you should return false if there is a problem, not exit.

To get this stuff right and do it efficiently, you have to read the problem very carefully and do exactly what it asks.
I am writing a function that reads the text file “smslog_eng.txt”
and creates a new file containing all posts coming from the phone
number 0702-235689.
As Handy Andy said, please post an example (just a few lines should be enough" of the input file. We can't help you filter out the lines if we don't know what their format is.

Also, I suspect that the general solution should NOT read the entire input file and then filter it out. That wastes lots of memory. Instead, open both input and output files. Then the function should:
1
2
3
4
5
readOneRecord;
if (theRecord matches theSender) {
    writeTheRecord;
}
repeat until end of file.
Hello nypran,

I was thinking.

There is no universal way to read a file. Every input file is different and every program that reads that file has to be don differently.

The way you code your program to read a file is based on what the file looks like and the information that needs to be read.

Here is a tip:

When posting code it is best to post the complete code so it can be compiled and run. Many times where you think there is a problem is not where it starts and with missing code no one has any idea what is wrong because they tend to assume that say information passed to a function is correct when it may not be.

If there is an input file post the file or at least a fair sample (say 5 or 6 lines) so everyone knows you are working with.

As dhayden has pointed out some of the problems with your function there are still problems with your code that do not follow the instructions.

In one place you say "0702-235689" and in use you use "0702 - 235689". Which is it?

You open the input file as "smslog_eng.txt", but the error message says "smslog_eng.dat". Again which is it?


Hope that helps,

Andy
@nypram, could you compile and run this program with your '.dat' file? This produces an 'output_dat.txt' file.
Please post this file here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <fstream>
#include <cctype>

const int MAX_LINE_LENGTH = 80;

using namespace std;

void printHelp()
{
     cout << "Usage: <prog_name> <input_file>\n"
          << "This produces an 'output_dat.txt' file.\n";
}

int main(int argc, char **argv)
{
    if (argc < 2) { printHelp(); return 1; }  
    ifstream ifs(argv[1]);
    if (!ifs) { printHelp(); return 2; }    
    ofstream ofs("output_dat.txt");
    if (!ofs) return 3;
    
    int linePos = 1;
    char data;
    while( ifs.get(data) )
    {
        if ( isgraph(data) || isspace(data) )
        {
             ofs.put(data);
        }
        else { ofs.put('x'); }
        ++linePos;
        
        if (data == '\n') linePos = 1;
              
        if (linePos == MAX_LINE_LENGTH)
        {
            ofs.put('\n');
            linePos = 1;
        }
    }
    return 0;
}
Last edited on
I reworked the program, now it's a little hex-printer :)

*edited
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cctype>

// How much chars get printed at a line.
const int MAX_ITEMS_PER_LINE = 16;

void printHelp()
{
     std::cout << "Usage: <prog_name> <input_file>\n"
          << "Prints a pseudo-hex to standard output (std::cout)\n";
}

std::string charToHex( char ch)
{
     char first, second;
     
     first = ch / 0x10;
     second = ch % 0x10;
     
     if (first < 10) { first += '0'; }
     else {
         first -= 10;
         first += 'A';
     }
     if (second < 10)  { second += '0'; }
     else {
         second -= 10;
         second += 'A';
     }
     return std::string() + first + second;
}

int main( int argc, char **argv)
{
    if (argc < 2) { printHelp(); return 1; }  
    std::ifstream is(argv[1]);
    if (!is) { printHelp(); return 2; }    
    std::ostream &os = std::cout;
    if (!os) return 3;

    long int lineNo = 0;    
    int column = 0;
    char data;
    while( is.get(data) )
    {
        if (column == 0)
        {
            os << std::setw(6) << std::hex 
               << lineNo * MAX_ITEMS_PER_LINE << ": ";
        }
        if (isgraph(data) )
        {
             os << " " << data << " ";
        }
        else if (data == 32) os << "   ";   // space
        else if (data == 10) os << "\\n ";  // new line
        else if (data == 7)  os << "\\a ";  // bell
        else if (data == 8)  os << "\\b ";  // backspace
        else if (data == 9)  os << "\\t ";  // horizontal tabtab
        else if (data == 11) os << "\\v ";  // vertical tab
        else if (data == 12) os << "\\f ";  // form feed
        else if (data == 13) os << "\\r ";  // carriage return
        else { os << charToHex(data) << " "; }
        ++column;
           
        if (column >= MAX_ITEMS_PER_LINE)
        {
            os.put('\n');
            column = 0;
            ++lineNo;
        }
    }
    os << '\n';
    return 0;
}


Now it prints the file content to console, but you could redirect the output to a file. At my Linux shell, it's
prog_name input_file > output_file
Last edited on
Topic archived. No new replies allowed.