Thread: Read from text file to a string

  1. #1
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53

    Read from text file to a string

    I am implementing a functionality where I have to send emails through code and have to read the email subject and body from a text file.

    This is how my text file looks like. The # switch indicates start of the message body.

    Code:
    Product Notification Reminder
    
    #
    Hello1,
    
    This is a reminder that the attached product notification tasks assigned to you are still open.
    
    This mail has been automatically generated. Please direct further enquiries to the owner of the tasks.
    
    Kind Regards,
    
    Admin
    I have implemented the code as

    Code:
    void get_envelope_subject_body(static std::string &strEnvSubject, static std::string &strEnvBody)
    {
        FILE *fpEnvelopeConfig = NULL;
        char cBuffer[100];
        char *pcMessage = NULL;
        char *pcSubject = NULL;
        int iCount = 0;
        bool isSubject = true;
    
        if ((fpEnvelopeConfig = fopen("D:\\Configfile.txt", "r")) == NULL)
        {
            printf("Cannot open the envelope configuration file.");
        }
        else
        {
            pcSubject = (char*)malloc(sizeof(cBuffer));
            pcSubject[0] = '\0';
    
            while (fgets(cBuffer, sizeof(cBuffer), fpEnvelopeConfig) != NULL)
            {
    
                if (isSubject == true && cBuffer[0] != '#')
                {
                    strcat(pcSubject, cBuffer);
                }
    
    	    //end of subject, start of body
                if (cBuffer[0] == '#')
                {
                    isSubject = false;
                }
    
                if (isSubject == false && cBuffer[0] != '#')
                {
                    iCount++;
                    pcMessage = (char*)realloc(pcMessage, iCount *sizeof(cBuffer));
    
                    if (iCount == 1)
                    {
                        pcMessage[0] = '\0';
                    }
    
                    strcat(pcMessage, cBuffer);
                }
            }
        }
    
        strEnvSubject = pcSubject;
        strEnvBody = pcMessage;
    
        free(pcMessage);
        free(pcSubject);
    }
    I am sure there is a better way to write this code and optimize it further so please let me know your comments/suggestions.


    Also, the code will be run in Unix whereas I am developing it in windows. So, is the code portable?

  2. #2
    Registered User
    Join Date
    Sep 2001
    Posts
    4,912
    Moved to the C++ forum

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Since you're reading into a C++ string, I would use ifstream. A call to getline with # as the delimiter gets the subject, and then read the rest into the message.

    Are you familiar with C++ file stream classes?

  4. #4
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    Thanks for your reply Daved. I am not familiar with C++ file stream classes. I will checkout some tutorials on the same and try to update my code.

  5. #5
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53

    Thumbs up

    I tried

    Code:
    void get_envelope_subject_body(static std::string &strEnvSubject, static std::string &strEnvBody)
    {
        ifstream fpEnvelopeConfigFile("D:\\EnvelopeConfig.txt");
    	
        if(!fpEnvelopeConfigFile.is_open()) 
        {
            printf("Cannot open the envelope configuration file.");
        }
        else
        {
            string line;
            string strSubject;
    	string strBody;
    	
    	while(getline(fpEnvelopeConfigFile, line))
    	{
    		getline(fpEnvelopeConfigFile, strSubject, '#') ;
    		getline(fpEnvelopeConfigFile, strBody) ;
    	}
            strEnvSubject = strSubject;
    	strEnvBody = strSubject;
        }
    }
    The string strSubject holds the entire file contents whereas strBody is empty.

    What am I doing wrong here?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Why do you declare the parameters to be static?

    Quote Originally Posted by lazyme
    The string strSubject holds the entire file contents whereas strBody is empty.
    Notice that you pretty much throw away whatever was read into line.

    What you probably want to do is this: keep reading lines and append them to strEnvSubject until you encounter the first '#'. After that, keep reading lines and append them to strEnvBody until the end of the file is reached.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    I changed the code to

    Code:
    else
    {
    	string strSubject;
    	string strBody;
    	
    	while(getline(fpEnvelopeConfigFile, strSubject, '#'))
    	{
    		strEnvSubject+=strSubject;
    		
    		while(getline(fpEnvelopeConfigFile, strBody))
    		{
    			strEnvBody+=strBody;
    		}
    	}
    }
    The code now works fine. The only problem is the indentation in the text file is not retained. How can I retain the indentation?

    Also, is there a problem in using static strings in my code?

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> I am not familiar with C++ file stream classes. I will checkout some tutorials on the same and
    >> try to update my code.

    That's pretty good for your first time.

    You know that the very first '#' will indicate the end of the subject, so instead of making that first read a while loop, I would just use an if(!getline(...)) and put an error message if it fails to find the #.

    After that, you are using a getline loop to get each line. By default, getline reads until it sees the '\n' newline character. It then discards that character. To get the newlines back in to the text body, just add '\n' to the end of the line inside the loop.

    There are other ways you might be able to read in the entire body all at once, but I think this solution is just fine.

    >> Also, is there a problem in using static strings in my code?
    It's not necessary. Is there a reason you are doing it?

  9. #9
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    >>It's not necessary. Is there a reason you are doing it?
    No, there isn't. I have changed that now.

    I made a few changes. How does my code look now?

    Code:
    if(!getline(fpEnvelopeConfigFile, strSubject, '#').eof())
    {
    	strEnvSubject=strSubject;	
    	while(getline(fpEnvelopeConfigFile, strBody) )
    	{
    		{
    			strBody.append("\n");
    			strEnvBody.append(strBody);
    		}
    	}
    }
    else
    {
    	setDefaultValues = true;
    	printf("\n\nMessage subject not found\n");
    }
    Also, I couldn't a built-in C++ function to delete the leading and trailing white spaces from a string. What is a good way of doing that?

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> How does my code look now?
    Looks good. At first glance I like what you did with eof to make sure that the '#' was found. What happens if there is no '#'? Is the entire text the subject? Is it the body? Or is the entire email bad? Your code appears to indicate that it means the entire email is bad, but if it is one of the other two then I guess the strSubject string will contain the contents when you're in the else.

    >> I couldn't a built-in C++ function to delete the leading and trailing white spaces from a string.
    There might be a better way, but my first thought is to use find_first_not_of("\n\t ") and find_last_not_of("\n\t "). Then use those values with substr to get the substring without whitespace. I think substr takes the first character you want and then the count, so you'll have to do some subtraction in there to get it just right.

  11. #11
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    If there is no # found,, I have set a boolean setDefaultValues = true.
    When this boolean is true, I am setting default values for the strEnvSubject and strEnvBody.

    >>There might be a better way, but my first thought is to use find_first_not_of("\n\t ") and >>find_last_not_of("\n\t "). Then use those values with substr to get the substring without >>whitespace. I think substr takes the first character you want and then the count, so you'll >>have to do some subtraction in there to get it just right.

    I will try to implement the same and post my code here.

  12. #12
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    How does my trim function look like?

    Code:
    void trim( std::string& strToBeFormatted )
    {
    	size_t startPos = strToBeFormatted.find_first_not_of("\n\t ");
    
    	if(startPos==std::string::npos)
    	{
    		startPos = 0;
    	}
    
    	size_t endPos = strToBeFormatted.find_last_not_of("\n\t ");
    
    	if(endPos!=std::string::npos)
    	{
    		endPos =  (endPos+1)-startPos;
    	}
    
    	strToBeFormatted = strToBeFormatted.substr( startPos, endPos );
    }
    Last edited by lazyme; 05-10-2009 at 02:19 AM.

  13. #13
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    If startPos is string::npos, doesn't that just mean that the whole string is whitespace?

    If endPod is string::npos doesn't that also just mean the whole string is whitespace?

  14. #14
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    ^^
    Yes, isn't my code good enough to handle that condition?

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by lazyme
    Yes, isn't my code good enough to handle that condition?
    No, since it would leave the string as-is rather than truncate it to an empty string.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Newbie homework help
    By fossage in forum C Programming
    Replies: 3
    Last Post: 04-30-2009, 04:27 PM
  2. Basic text file encoder
    By Abda92 in forum C Programming
    Replies: 15
    Last Post: 05-22-2007, 01:19 PM
  3. Replies: 4
    Last Post: 03-03-2006, 02:11 AM
  4. Replies: 1
    Last Post: 09-10-2005, 06:02 AM
  5. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM