Thread: Text file - new line issue

  1. #1
    Registered User
    Join Date
    Jun 2012
    Posts
    127

    Text file - new line issue

    Code:
    if (feof(inSalesPtr) != "\n")
                fprintf(inSalesPtr,"\n");
    How to design a if statement to achieve the following goal?
    1)
    Text file - new line issue-sales-jpg
    insert a new line

    2)
    Text file - new line issue-sales2-jpg
    do nothing

  2. #2
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Untested:

    Code:
    FILE *inSalesPtr;
    
    //open the file for binary read/append
    if ((inSalesPtr = fopen("sales.txt", "a+b")) == NULL) exit(1); /* exit on error */
    
    // set the file position to the very last character
    if (fseek(inSalesPtr, -1, SEEK_END)) exit(2); /* exit on error */
    
    // read the last character
    int ch = fgetc(inSalesPtr);
    if (ch == EOF) exit(3); /* exit on error */
    
    // check if the last character is a '\n'
    if (ch != '\n') {
        // if the last character is not a '\n' append a "\r\n" (Windows line break)
        fputs("\r\n", inSalesPtr);
    }
    
    // close the FILE
    fclose(inSalesPtr);
    Last edited by qny; 11-03-2012 at 03:27 AM. Reason: typo

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    If you pulled in the data using fscanf(), ( or from a buffer, using sscanf() ), then you know you need to add the newline.

    So when would you NOT need to enter the newline into the file output?

    !feof is a problem - using the return number from fscanf() or sscanf(), like I showed you previously.

  4. #4
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    // number of salesman 
    #define SIZE 100
    // salesman_type structure definition
    typedef struct{
    		int ID; // salesman id
    		char id_txt[6]; // salesman id for txt file
    		char name[50]; // salesman name
    		double hor_total; // total sales amount of a salesman  
    	}salesman_type; // end structure salesman_type
    
    
    salesman_type salesman[SIZE];// synonym for salesman_type 
    
    
    // function prototype
    int nextId(int currentId, int isReset);
    int sale_menu(); 
    int report_menu(); 
    void AddSalesMan(int initialId); 
    
    
    // function to generate id
    // currentId and isReset are parameters
    int nextId(int currentId, int isReset)
    {
    	// initializes elements to 0 for the first time function is called
    	static int lastId = 0;
    	// if isReset is 0, assign currentId to lastId;
    	if (isReset == 0)
    	{
    		lastId = currentId;
    	}
    	//if isReset is not 0, return and add 1 to lastId 
    	if (isReset != 0)
    		return ++lastId;
    }
    // sales processing system menu function
    int sale_menu()
    {
    	int menu;
    	printf("Sales Processing System\n");
    	printf("-----------------------\n\n");
    	printf("1. Add Salesman Records\n");
    	printf("2. Reports Generation\n");
    	printf("3. Modify Salesman Records\n");
    	printf("4. Delete Salesman Records\n\n");
    	printf("0. Exit\n");
    	printf("Your choice: ");
    	scanf("%d", &menu);
    	return menu;
    	printf("\n");
    }
    // reports generation menu function
    int report_menu()
    {
    	int report;
    	printf("Reports Generation\n");
    	printf("------------------\n\n");
    	printf("1. View Quarterly Sales Report\n");
    	printf("2. View Individual Salesman Commission\n\n");
    	printf("0. Return to Main Menu\n");
    	printf("Your choice: ");
    	scanf("%d", &report);
    	return report;
    }
    // function to add salesman
    void AddSalesMan(int initialId)
    {
    	// nextid.txt file pointer
    	FILE *writeIdPtr;
    	// sales.txt file pointer
    	FILE *inSalesPtr;
    	char ch;
    	int a, b; // counter
    	int loop = 1; // confirmation
    	int creId = 1; // pass value to nextId function to generate ID
    	int newId; // receive new generated ID
    	double sale[SIZE][4]; // quarterly sales amount
    
    
    	// fopen opens file; exit program if unable to create file
    	if ( (writeIdPtr = fopen("nextid.txt","w") ) == NULL)
    	{
    		printf("Cannot open nextid.txt.\n"); // display error message 
    		system("pause"); // pause program before it exits
    		exit(-1); // end program
    	} //end if
    	// fopen opens file; exit program if unable to create file
    	if ( (inSalesPtr = fopen("sales.txt","a") ) == NULL)
    	{
    		printf("Cannot open sales.txt file.\n"); // display error message 
    		system("pause"); // pause program before it exits
    		exit(-1); // end program
    	} // end if
    	else
    	{
    		// set the file position to the very last character
    		fseek(inSalesPtr, -1, SEEK_END);
    		ch = fgetc(inSalesPtr);
    		if (ch != '\n')
    		{
    			fputs("\r\n",inSalesPtr);
    		}
    		// write salesname id, quarterly sales amount into file with fprintf	
    		for(a=initialId - 1; a<SIZE; a++)
    		{
    			// while loop is 1
    			while (loop == 1)
    			{
    				// assign new generated id to newId
    				newId = nextId(initialId, creId);
    				// write newId into file with fprintf
    				fprintf(inSalesPtr,"S%04d|",newId); 
    				//printf("Name: ");
    				//scanf(" %[^\n]", salesman[a].name);
    				for (b=0; b<4; b++)
    				{
    					// prompt and read quarterly sales amount
    					printf("Quarter %d: ",b+1); 
    					scanf(" %lf", &sale[a][b]);
    					// write sales[a][b] into file with fprintf
    					if(b<3)
    						fprintf(inSalesPtr,"%.2f|",sale[a][b]);
    					// end if
    					else
    						fprintf(inSalesPtr,"%.2f\n",sale[a][b]);
    					// end else
    				} // end for	
    				printf("\n");
    				printf("Continue?(Yes = 1): "); // prompt user to continue or not
    				scanf("%d",&loop);
    			} // end while 
    		} // end for
    		// write newId into file with fprintf
    		fprintf(writeIdPtr,"%d",newId);
    		fclose(writeIdPtr); // flose close the file
    		fclose(inSalesPtr); // flose close the file
    	} // end else
    } // end function AddSalesman 
    
    
    // function main begins program execution
    void main()
    {
    	// nextid.txt file pointer 
    	FILE *readIdPtr;
    	// variable declaration
    	int a, b, c = 0, last; // counter
    	int getMenu = 0, getReport = 0; // menu selector
    	double ver_total = 0, max = 0; 
    	int id = 0, lastId, resetId = 0;
    
    
    	// fopen opens the file; exits program if file cannot be opened
    	if ( (readIdPtr = fopen("nextid.txt","r") ) == NULL)
    	{
    		printf("Cannot open nextid.txt file\n");
    		system("pause");
    		exit(-1);
    	} // end if
    	else
    	{
    		// read lastId from file
    		fscanf(readIdPtr,"%d",&lastId);
    		// Generate new id from previous salesman ID if the salesman is one or more
    		// lastId and restId are arguments
    		nextId(lastId, resetId);
    	} // end else
    	// fclose close the file
    	fclose(readIdPtr);
    	// call and assign sale_menu function to getMenu
    	getMenu = sale_menu();
    	printf("\n");
    	// Execute command based on user input
    	switch(getMenu)
    	{
    		// call AddSalesMan function
    		case 1:
    			AddSalesMan(lastId);
    			break;
    		// call and assign report_menu to getReport
    		case 2:
    			break;
    	} // end switch
    	system("pause"); // pause the program before it exits	
    } // end main
    Why it doesn't work?
    Attached Files Attached Files

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    WHAT isn't working right?

    Describe the problem like you did in the first post of this thread - that was good.

    It would be great to know if the advice given since then, has solved that first problem.

  6. #6
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Code:
        if ( (inSalesPtr = fopen("sales.txt","a") ) == NULL)
        {
            printf("Cannot open sales.txt file.\n"); // display error message
            system("pause"); // pause program before it exits
            exit(-1); // end program
        } // end if
        else
        {
            // set the file position to the very last character
            fseek(inSalesPtr, -1, SEEK_END);
            ch = fgetc(inSalesPtr);
    You opened the FILE for append mode, but then try to read from it ... this is a big no no: don't do that!
    Open the file for reading / appending in binary mode like I suggested
    Code:
        if ( (inSalesPtr = fopen("sales.txt", "a+b") ) == NULL)
    Note:
    the binary mode may be troublesome (or its absence may be troublesome).

    Without binary mode, when a file contains "one\r\ntwo\r\n" (10 characters) it is converted to "one\ntwo\n" (8 characters). Using fseek is not guaranteed to go to the expected place.
    With binary mode there is no conversion between what's on disk and what your program sees, so "one\r\ntow\r\n" is effectively read as "one\r\ntwo\r\n" and you have to deal with the '\r's yourself.

    My suggestion ,assuming you have to deal with Windows line breaks of "\r\n", is to open the files without the binary flag for normal processing, and open them with the binary flag for precision work within the disk-file itself.

  7. #7
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    945
    I'm beginning to think that ulti-killer either is a troll or has severe periodic amnesia (forgets everything from time to time).

  8. #8
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    Quote Originally Posted by qny View Post
    You opened the FILE for append mode, but then try to read from it ... this is a big no no: don't do that!
    Open the file for reading / appending in binary mode like I suggested
    Code:
        if ( (inSalesPtr = fopen("sales.txt", "a+b") ) == NULL)
    Note:
    the binary mode may be troublesome (or its absence may be troublesome).

    Without binary mode, when a file contains "one\r\ntwo\r\n" (10 characters) it is converted to "one\ntwo\n" (8 characters). Using fseek is not guaranteed to go to the expected place.
    With binary mode there is no conversion between what's on disk and what your program sees, so "one\r\ntow\r\n" is effectively read as "one\r\ntwo\r\n" and you have to deal with the '\r's yourself.

    My suggestion ,assuming you have to deal with Windows line breaks of "\r\n", is to open the files without the binary flag for normal processing, and open them with the binary flag for precision work within the disk-file itself.
    Change to a+b still the same result.

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    You can't open a file in append mode, and then try to read from the file.

    You can't fseek() to the end of the file, and then try to read from the file.

    I don't know how to make it any plainer than that.

  10. #10
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    Code:
    #include <stdio.h>#include <stdlib.h>
    #include <string.h>
    
    
    // number of salesman 
    #define SIZE 100
    // salesman_type structure definition
    typedef struct{
    		int ID; // salesman id
    		char id_txt[6]; // salesman id for txt file
    		char name[50]; // salesman name
    		double hor_total; // total sales amount of a salesman  
    	}salesman_type; // end structure salesman_type
    
    
    salesman_type salesman[SIZE];// synonym for salesman_type 
    
    
    // function prototype
    int nextId(int currentId, int isReset);
    int sale_menu(); 
    int report_menu(); 
    void AddSalesMan(int initialId); 
    
    
    // function to generate id
    // currentId and isReset are parameters
    int nextId(int currentId, int isReset)
    {
    	// initializes elements to 0 for the first time function is called
    	static int lastId = 0;
    	// if isReset is 0, assign currentId to lastId;
    	if (isReset == 0)
    	{
    		lastId = currentId;
    	}
    	//if isReset is not 0, return and add 1 to lastId 
    	if (isReset != 0)
    		return ++lastId;
    }
    // sales processing system menu function
    int sale_menu()
    {
    	int menu;
    	printf("Sales Processing System\n");
    	printf("-----------------------\n\n");
    	printf("1. Add Salesman Records\n");
    	printf("2. Reports Generation\n");
    	printf("3. Modify Salesman Records\n");
    	printf("4. Delete Salesman Records\n\n");
    	printf("0. Exit\n");
    	printf("Your choice: ");
    	scanf("%d", &menu);
    	return menu;
    	printf("\n");
    }
    // reports generation menu function
    int report_menu()
    {
    	int report;
    	printf("Reports Generation\n");
    	printf("------------------\n\n");
    	printf("1. View Quarterly Sales Report\n");
    	printf("2. View Individual Salesman Commission\n\n");
    	printf("0. Return to Main Menu\n");
    	printf("Your choice: ");
    	scanf("%d", &report);
    	return report;
    }
    // function to add salesman
    void AddSalesMan(int initialId)
    {
    	// nextid.txt file pointer
    	FILE *writeIdPtr;
    	// sales.txt file pointer
    	FILE *inSalesPtr;
    	char ch;
    	int a, b; // counter
    	int loop = 1; // confirmation
    	int creId = 1; // pass value to nextId function to generate ID
    	int newId; // receive new generated ID
    	double sale[SIZE][4]; // quarterly sales amount
    
    
    	// fopen opens file; exit program if unable to create file
    	if ( (inSalesPtr = fopen("sales.txt","a+b") ) == NULL)
    	{
    		printf("Cannot open sales.txt file.\n"); // display error message 
    		system("pause"); // pause program before it exits
    		exit(-1); // end program
    	} // end if
    	else
    	{
    		// set the file position to the very last character
    		fseek(inSalesPtr, -1, SEEK_END);
    		ch = fgetc(inSalesPtr);
    		if (ch != '\n')
    		{
    			fputs("\r\n",inSalesPtr);
    		}
    		fclose(inSalesPtr);
    	}
    	// fopen opens file; exit program if unable to create file
    	if ( (writeIdPtr = fopen("nextid.txt","w") ) == NULL)
    	{
    		printf("Cannot open nextid.txt.\n"); // display error message 
    		system("pause"); // pause program before it exits
    		exit(-1); // end program
    	} //end if
    	// fopen opens file; exit program if unable to create file
    	if ( (inSalesPtr = fopen("sales.txt","a") ) == NULL)
    	{
    		printf("Cannot open sales.txt file.\n"); // display error message 
    		system("pause"); // pause program before it exits
    		exit(-1); // end program
    	} // end if
    	else
    	{
    		// write salesname id, quarterly sales amount into file with fprintf	
    		for(a=initialId - 1; a<SIZE; a++)
    		{
    			// while loop is 1
    			while (loop == 1)
    			{
    				// assign new generated id to newId
    				newId = nextId(initialId, creId);
    				// write newId into file with fprintf
    				fprintf(inSalesPtr,"S%04d|",newId); 
    				//printf("Name: ");
    				//scanf(" %[^\n]", salesman[a].name);
    				for (b=0; b<4; b++)
    				{
    					// prompt and read quarterly sales amount
    					printf("Quarter %d: ",b+1); 
    					scanf(" %lf", &sale[a][b]);
    					// write sales[a][b] into file with fprintf
    					if(b<3)
    						fprintf(inSalesPtr,"%.2f|",sale[a][b]);
    					// end if
    					else
    						fprintf(inSalesPtr,"%.2f\n",sale[a][b]);
    					// end else
    				} // end for	
    				printf("\n");
    				printf("Continue?(Yes = 1): "); // prompt user to continue or not
    				scanf("%d",&loop);
    			} // end while 
    		} // end for
    		// write newId into file with fprintf
    		fprintf(writeIdPtr,"%d",newId);
    		fclose(writeIdPtr); // flose close the file
    		fclose(inSalesPtr); // flose close the file
    	} // end else
    } // end function AddSalesman 
    
    
    // function main begins program execution
    void main()
    {
    	// nextid.txt file pointer 
    	FILE *readIdPtr;
    	// variable declaration
    	int a, b, c = 0, last; // counter
    	int getMenu = 0, getReport = 0; // menu selector
    	double ver_total = 0, max = 0; 
    	int id = 0, lastId, resetId = 0;
    
    
    	// fopen opens the file; exits program if file cannot be opened
    	if ( (readIdPtr = fopen("nextid.txt","r") ) == NULL)
    	{
    		printf("Cannot open nextid.txt file\n");
    		system("pause");
    		exit(-1);
    	} // end if
    	else
    	{
    		// read lastId from file
    		fscanf(readIdPtr,"%d",&lastId);
    		// Generate new id from previous salesman ID if the salesman is one or more
    		// lastId and restId are arguments
    		nextId(lastId, resetId);
    	} // end else
    	// fclose close the file
    	fclose(readIdPtr);
    	// call and assign sale_menu function to getMenu
    	getMenu = sale_menu();
    	printf("\n");
    	// Execute command based on user input
    	switch(getMenu)
    	{
    		// call AddSalesMan function
    		case 1:
    			AddSalesMan(lastId);
    			break;
    		// call and assign report_menu to getReport
    		case 2:
    			break;
    	} // end switch
    	system("pause"); // pause the program before it exits	
    } // end main
    Before
    Text file - new line issue-sales2-jpg

    After
    Text file - new line issue-output-3-jpg

  11. #11
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    Quote Originally Posted by ulti-killer View Post
    [CODE]
    Before
    Text file - new line issue-sales2-jpg

    After
    Text file - new line issue-output-3-jpg
    Is this the expected outcome?

  12. #12
    Registered User
    Join Date
    Jun 2012
    Posts
    127
    No. My goal is:
    Text file - new line issue-output-4-jpg

    No matter how the user put line indicator in last line text or any blank line, the new input record can stick with the old record.

  13. #13
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    My code works for me:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int eofnormalize(const char *fname) {
      FILE *h;
      int ch;
    
      if ((h = fopen(fname, "a+b")) == NULL) return 1;
      if (fseek(h, -1, SEEK_END)) return 2;
      ch = fgetc(h);
      if (ch == EOF) return 3;
      if (ch != '\n') {
        fputs("\r\n", h);
      }
      if (fclose(h)) return 4;
      return 0;
    }
    
    int main(void) {
      FILE *h;
    
      if ((h = fopen("151926.dat", "wb")) == NULL) exit(1);
      fprintf(h, "1 no line break"); /* not a line */
      if (fclose(h)) exit(2);
    
      if (eofnormalize("151926.dat")) exit(3);
    
      if ((h = fopen("151926.dat", "a")) == NULL) exit(4);
      fprintf(h, "2 ok\n");
      fclose(h);
    
      if ((h = fopen("151926.dat", "a")) == NULL) exit(5);
      fprintf(h, "3 windows line break\r\n");
      if (fclose(h)) exit(6);
    
      if (eofnormalize("151926.dat")) exit(7);
    
      if ((h = fopen("151926.dat", "a")) == NULL) exit(8);
      fprintf(h, "4 ok\n");
      fclose(h);
    
      return 0;
    }
    Code:
    ./a.out && echo $? && hd 151926.dat
    0
    00000000  31 20 6e 6f 20 6c 69 6e  65 20 62 72 65 61 6b 0d  |1 no line break.|
    00000010  0a 32 20 6f 6b 0a 33 20  77 69 6e 64 6f 77 73 20  |.2 ok.3 windows |
    00000020  6c 69 6e 65 20 62 72 65  61 6b 0d 0a 34 20 6f 6b  |line break..4 ok|
    00000030  0a                                                |.|
    00000031
    If I remove the eofnormalize() calls
    Code:
    ./a.out && echo $? && hd 151926.dat
    0
    00000000  31 20 6e 6f 20 6c 69 6e  65 20 62 72 65 61 6b 32  |1 no line break2|
    00000010  20 6f 6b 0a 33 20 77 69  6e 64 6f 77 73 20 6c 69  | ok.3 windows li|
    00000020  6e 65 20 62 72 65 61 6b  0d 0a 34 20 6f 6b 0a     |ne break..4 ok.|
    0000002f

  14. #14
    Registered User
    Join Date
    Sep 2012
    Posts
    357
    In eofnormalize(), a call to a file positioning function is needed between input and output.
    I no longer can edit my post, but I'd change the function to:

    Code:
    #include <stdio.h>
    
    int eofnormalize(const char *fname) {
      FILE *h;
      int ch;
     
      if ((h = fopen(fname, "a+b")) == NULL) return 1;
      if (fseek(h, -1, SEEK_END)) return 2;
      ch = fgetc(h);
      if (ch == EOF) return 3;
      if (ch != '\n') {
        fseek(h, 0, SEEK_CUR);
        fputs("\r\n", h);
      }
      if (fclose(h)) return 4;
      return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 9
    Last Post: 11-11-2011, 10:32 PM
  2. Replies: 3
    Last Post: 05-25-2011, 05:54 PM
  3. Replies: 8
    Last Post: 05-05-2010, 02:43 PM
  4. Replies: 1
    Last Post: 10-30-2002, 05:45 AM
  5. Replies: 4
    Last Post: 06-22-2002, 12:23 PM