Text written to Console after reading from .txt file using streamreader only partially appearing

StackOverflow https://stackoverflow.com/questions/23094388

  •  04-07-2023
  •  | 
  •  

Question

I'm trying to search for a customer account stored in a text file by the town they live in. There are three customer accounts all with different towns. I think the program finds the correct customer as it does returns data to write to the screen but not all of it. These images explain it better. Tried to embed them but don't have the points

The text file contents:

enter image description here

When searching for the customer that lives in Liverpool(Although the image doesnt show it, the cursor starts blinking 5 lines below the DOB)

http://i1370.photobucket.com/albums/ag266/Aaron_McCauley/2_zpsb6561828.png

Searching for Belfast customer. Notice it picks up the coreect DOB but wrong customer number and Surname.(Ill put the link in the commentit won't let me post more than 2 links)

Heres the code of the method::

static void FindTown(CustomerStruct[] CustomerDeats)
    {
        string City;
        bool CityMatch = false;
        Console.Clear();

    begin:
        try
        {
            Console.WriteLine("Please enter the customers Town ");
            City = Console.ReadLine();                
        }
        catch
        {
            Console.WriteLine("Failed. Please try again.");
            goto begin;
        }

        var pathToTown = @"..\..\..\Files\Customer.txt";

        using (StreamReader sr = new StreamReader(pathToTown))

            while (!CityMatch)
            {

                {
                    RecCount = 0;

                    CustomerDeats[RecCount].Town = sr.ReadLine();

                    if (City == CustomerDeats[RecCount].Town)
                    {

                        Console.WriteLine("\n\n");

                        CityMatch = true;



                        CustomerDeats[RecCount].CustomerNo = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].CustomerNo);

                        CustomerDeats[RecCount].Surname = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].Surname);

                        CustomerDeats[RecCount].Forename = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].Forename);

                        CustomerDeats[RecCount].Street = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].Street);

                        CustomerDeats[RecCount].Town = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].Town);

                        CustomerDeats[RecCount].DOB = sr.ReadLine();
                        Console.WriteLine(CustomerDeats[RecCount].DOB);

                        Console.ReadKey();


                    }

                    RecCount++;

                }

            }
    }
Was it helpful?

Solution 2

You are searching for the line that contains the town, after you find it you read the next five lines immediately.But the problem is your informations comes before the town, you need to read the four line that comes before the town, and the line that comes after the town (date).

Here is a way of doing this but not so elegant.You can use a temporary list to store readed lines then when you find the record that you are looking for display the previous items (lines) of the list like this:

using (StreamReader sr = new StreamReader(pathToTown))
{
    var tempLines = new List<string>();
    while (!CityMatch && !sr.EndOfStream)
    {

        string line = sr.ReadLine();

        if (City == line)
        {
            Console.WriteLine("\n\n");
            CityMatch = true;
            int count = tempLines.Count;
            Console.WriteLine("Customer No: {0}", tempLines[count-4]);
            Console.WriteLine("Customer Surname: {0}", tempLines[count - 3]);
            Console.WriteLine("Customer Forename: {0}", tempLines[count - 2]);
            Console.WriteLine("Customer Street: {0}", tempLines[count - 1]);
            Console.WriteLine("Customer Town: {0}", line);
            Console.WriteLine("Customer Day Of Birth: {0}", sr.ReadLine());
            Console.ReadKey();

        }else tempLines.Add(line);

    }
}

You can apply this logic to your code.BTW, I have also added another condition to your while loop in order to save you from having an infinite loop. (!sr.EndOfStream) that will break the loop if you reach the end of the stream, if you type a town that is not exists in your file then your loop will be infinite because CityMatch will never gonna change.

Just for the variety here is another way using LINQ:

 var town = Console.ReadLine();
 var record = File.ReadLines("filepath")
              .Where(x => x != string.Empty)
              .Select((line, idx) => new {line, idx})
              .GroupBy(x => x.idx/6)
              .FirstOrDefault(x => x.Any(e => e.line.Contains(town)));

if (record != null)
{
     var values = record.Select(x => x.line).ToArray();
     Console.WriteLine("Customer No: {0}", values[0]);
     Console.WriteLine("Customer Surname: {0}", values[1]);
     Console.WriteLine("Customer Forename: {0}", values[2]);
     Console.WriteLine("Customer Street: {0}", values[3]);
     Console.WriteLine("Customer Town: {0}", values[4]);
     Console.WriteLine("Customer Day Of Birth: {0}", values[5]);
}

OTHER TIPS

The first thing I would do if I were you would be to better understand the way that StreamReader works. Everytime you call ReadLine() your position within the file will advance another line. I would rethink your algorithm. Maybe something along the lines of:

  1. Read all lines in the file and split on the empty line.
  2. Store the non-empty lines in some sort of object that contains all the information.
  3. Search through your objects to find what you are looking for (ex: Town == Liverpool).

Attempting to do this while reading through the file will become difficult if you don't understand how reading a file works.

Just a thought. :-)

Your problem lies in here:

CustomerDeats[RecCount].Town = sr.ReadLine();

if (City == CustomerDeats[RecCount].Town)

The if will only be true once you've read in the correct city name. Based upon your file, that means you will only read the last line of the file, and then Write it to the console.

As an aside, providing a name not found in the file will result in an infinite loop.

You start reading a customer's data when the reader reaches a city, but there only 1 record's field goes after the city. Consider read all the data into the memory first. For instance - into the array. Something like this:

string s = File.ReadAllText(pathToTown).Trim();
string[] customersUnparsed = s.Split(new[] { Environment.NewLine + Environment.NewLine },
    StringSplitOptions.RemoveEmptyEntries);
string[][] customers = Array.ConvertAll(customersUnparsed,
    c => c.Split(new[] { Environment.NewLine }, StringSplitOptions.None));

Usage example:

string[] customer = Array.Find(customers, c => c[4] == "Liverpool");

This code is not perfect enough. I realize that it's much better to create a class or a struct for the customer, but I believe it may point you to the right direction.

First a word of warning your code will enter an infinite loop if the word entered by the user is not in the file. In your example it is Liverpool You need to check for EndOfStream too. http://msdn.microsoft.com/en-us/library/vstudio/system.io.streamreader.endofstream

The ReadLine method reads a line and advances the pointer. http://msdn.microsoft.com/en-us/library/vstudio/system.io.streamreader.readline

In your sample code here is what is being read into the property Town until it encounters Liverpool. This is at every read line into town.

Town is "1000", Town is "Ramsey", Town is "Aaron", Town is "10 Mews Park", Town is "Cardiff", Town is "03/07/1989", Town is "1001", Town is "Cole", Town is "Joe", Town is "10 The Meadows", Town is "Belfast", Town is "04/06/1969", Town is "1002", Town is "Whilshere", Town is "Jack", Town is "9 Bishop Stream", Town is "Liverpool"

Keep in mind that the file pointer is being advanced every time you ReadLine.

As you can see from you output screenshot that only the DOB of the final record is printed. This is because, as demonstrated above, that all the data in the file has been consumed from the stream.

Also the final value of RecCount will always be 1. You reset it to 0 at the begining of every iteration of the loop.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top