user3330371
user3330371

Reputation: 11

Reading multiple records kept in a text file

Basically i have the user open a text document that is formatted like this currently.

Burger.jpg,Double Down KFC,Food,30/06/95,This is a burger

it then splits the info into an array then into variables and then into text boxes.

obviously if i wanted multiple records i may have to format it differently, (thats what i need help with)

But if i had it like this what would be the most efficient way of taking these records from the text file and storing them separately so i can flick through them. For example with a combo box on my form. When the record is selected the form populates with that records data.

multiple records:

Burger.jpg,Double Down KFC,Food,30/06/95,This is a burger

Person.jpg,Smile,People,23/06/95,This is a Person

Here is my code currently for this part.

private void LoadFile()
{
    StreamReader reader = new StreamReader(fileName);

    content = reader.ReadLine();

    doc = content.Split(',');

    filename = Convert.ToString(doc[0]);
    fileNameTextBox.Text = doc[0];

    description = doc[1];
    descriptionTextBox.Text = doc[1];

    category = doc[2];
    categoryComboBox.Text = doc[2];

    //dateTaken = Convert.ToDouble(doc[3]);
    dateTakenTextBox.Text = doc[3];

    comments = doc[4];
    commentsTextBox.Text = doc[4];
}

This code currently works but only for the first record as it is using one array, and i obviously will need multiple ways of storing the other lines.

I Think the best option if i was going to give it a guess would be to use a List of some sort with a Class that generates Records, but that is where i am stuck and need help. (usually my questions on here get downvoted as i am not concise enough if that is the case comment and i will try to alter my question.

Thanks everyone.

Upvotes: 0

Views: 335

Answers (4)

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112324

I would create a class that holds the information of a record

public class ImageInfo
{
    public string FileName { get; set; }
    public string Description { get; set; }
    public string Category { get; set; }
    public DateTime Date { get; set; }
    public string Comments { get; set; }

    public override string ToString()
    {
        return FileName;
    }
}

Now you can write a method that returns the image infos

public List<ImageInfo> ReadImageInfos(string fileName)
{          
    string[] records = File.ReadAllLines(fileName);
    var images = new List<ImageInfo>(records.Length);
    foreach (string record in records) {
        string[] columns = record.Split(',');
        if (columns.Length >= 5) {
            var imageInfo = new ImageInfo();
            imageInfo.FileName = columns[0];
            imageInfo.Description = columns[1];
            imageInfo.Category = columns[2];

            DateTime d;
            if (DateTime.TryParseExact(columns[3], "dd/MM/yy", 
                CultureInfo.InvariantCulture, DateTimeStyles.None, out d))
            {
                imageInfo.Date = d;
            }

            imageInfo.Comments = columns[4];

            images.Add(imageInfo);
        }
    }
    return images;
}

Now you can fill the textboxes with one of these records like this

List<ImageInfo> images = ReadImageInfos(fileName);
if (images.Count > 0) {
    ImageInfo image = images[0];
    fileNameTextBox.Text = image.FileName;
    descriptionTextBox.Text = image.Description;
    categoryComboBox.Text = image.Category;
    dateTakenTextBox.Text = image.Date.ToShortDateString();
    commentsTextBox.Text = image.Comments;
}

The advantage of this approach is that the two operations of reading and displaying the records are separate. This makes it easier to understand and modify the code.


You can add ImageInfo objects to a ComboBox or ListBox directly instead of adding file names if you override the ToString method in the ImageInfo class.

public override string ToString()
{
    return FileName;
}

Add the items to a combo box like this:

myComboBox.Items.Add(image); // Where image is of type ImageInfo.

You can retrieve the currently selected item with:

ImageInfo image = (ImageInfo)myComboBox.SelectedItem;

Most likely you will be doing this in the SelectedIndexChanged event handler.

void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
    ImageInfo image = (ImageInfo)myComboBox.SelectedItem;
    myTextBox.Text = image.FileName;
}

Upvotes: 1

Jeggs
Jeggs

Reputation: 196

Create a class that resembles a row of your data, then iterate over the file, making your split and constructing a new class instance with your split data. Store this in a List<> (or some other appropriate structure) ensure you store it such that it can be referenced later. Don't change your UI as you are loading and parsing the file (as Mike has suggested), also as mike suggests you need to read until the EOF is reached (plenty of examples of this on the web) MSDN example.

Also, streamreader implements IDisposable, so you need to dispose of it, or wrap it in a using statement to clean up.

Example class, you could even pass the row in as a constructor argument:

public class LineItem
{
    public string FileName { get; set; }
    public string Description { get; set; }
    public string Category { get; set; }
    public DateTime DateTaken { get; set; }
    public string Comments { get; set; }

    public LineItem(string textRow)
    {
        if (!string.IsNullOrEmpty(textRow) && textRow.Contains(','))
        {
            string[] parts = textRow.Split(',');
            if (parts.Length == 5)
            {
                // correct length
                FileName = parts[0];
                Description = parts[1];
                Category = parts[2];
                Comments = parts[4];

                // this needs some work
                DateTime dateTaken = new DateTime();
                if (DateTime.TryParse(parts[3], out dateTaken))
                {
                    DateTaken = dateTaken;
                }
            }
        }
    }
}

Upvotes: 1

Ben
Ben

Reputation: 2523

If you keep all your entries the same:

name,food,type,blah blah
name,food,type,blah blah

you can add another split into your code:

line = content.Split('\n');
foreach (line in filename)
{
    doc = line.Split(',');
    //do stuff...

As for the option for string multiple entries, a method I have used is implementing a list of Models:

class ModelName
{
    string Name { get; set; }
    string foodType { get; set; }
    //etc...

    public void ModelName()
    {
        Name = null;
        foodType = null;
        //etc...
    }
}

List<Model> ModelList;
foreach (line in filename)
{
    doc = line.Split(',');
    Model.Name = doc[1];
    //etc...

And have a different list, and a different Model for each type of entry (person or food)

Upvotes: 0

Mike Weber
Mike Weber

Reputation: 311

Your code is not iterating through the records within the file.

You want to continue reading until the end of the file.

while (content != eof)
{
    // split content
    // populate text boxes
}

But this will overwrite your text boxes with each pass of the loop. Also, you want to separate your code - do not mix I/O process with code that updates the UI. The name of the method implies you are loading a file, but the method is doing far more than that. I would suggest changing the method to read the file, split each record into a class object which then gets stored into an array - and return that array.

A separate method will take that array and populate your table or grid or whatever is in the UI. Ideally, you have the gridview bind to the array.

Upvotes: 0

Related Questions