0

I am a beginner in programming,It's really difficult for me to analyze and debug how to skip reading the first line of the csv file. I need some help.
I need my id to fill my combobox in my form that contains all Id's.In order to not include the header in browsing and displaying.I need to skip the first line.

    public bool ReadEntrie(int id, ref string name, ref string lastname, ref 
    string phone, ref string mail, ref string website)
    {
        int count = 0;
        CreateConfigFile();
        try
        {
            fs = new FileStream(data_path, FileMode.Open);
            sr = new StreamReader(fs);
            string temp = "";
            bool cond = true;
            while (cond == true)
            {
                if ((temp = sr.ReadLine()) == null)
                {
                    sr.Close();
                    fs.Close();
                    cond = false;
                    if (count == 0)
                        return false;
                }
                if (count == id)
                {
                    string[] stringSplit = temp.Split(',');
                    int _maxIndex = stringSplit.Length;
                    name = stringSplit[0].Trim('"');
                    lastname = stringSplit[1].Trim('"');
                    phone = stringSplit[2].Trim('"');
                    mail = stringSplit[3].Trim('"');
                    website = stringSplit[4].Trim('"');
                }
                count++;
            }
            sr.Close();
            fs.Close();
            return true;
        }
        catch
        {
            return false;
        }
    }
Sam
  • 15
  • 2
  • 11
  • 1
    You could use `var line = File.ReadLines(fileName).Skip(id).FirstOrDefault()` instead of bothering with the streams to get the one line you want. If id > 0 then you'd always skip the first row, but if id could be 0 then you'd just do `Skip(id + 1)` instead. – juharr Jun 03 '17 at 03:57
  • There are few bugs: 1) In the block `if` where you set `cond` to false, you are closing `sr` and `fs`, but when the count is not `0` you close it again when you end `while` loop. I guess that it will cause exception. 2) The same case as previous, but it will fail earlier in the next `if` statement. When the `temp` is `null` and with a lot of bad luck the `count` equals `id` then you are trying to access `null.Split(',');` but it causes exception. I would recomend to extend `if (count == 0) return false;` with `else return true;` – Jirka Picek Jun 03 '17 at 04:02

2 Answers2

1

@Somadina's answer is correct, but I would suggest a better alternative. You could use a CSV file parser library such as CSV Helpers.

You can get the library from Nuget or Git. Nuget command would be:

Install-Package CsvHelper

Declare the following namespaces:

using CsvHelper;
using CsvHelper.Configuration;

Here's how simple your code looks when you use such a library:

class Program
{
    static void Main(string[] args)
    {
        var csv = new CsvReader(File.OpenText("Path_to_your_csv_file"));
        csv.Configuration.IgnoreHeaderWhiteSpace = true;
        csv.Configuration.RegisterClassMap<MyCustomObjectMap>();
        var myCustomObjects = csv.GetRecords<MyCustomObject>();

        foreach (var item in myCustomObjects.ToList())
        {
            // Apply your application logic here.
            Console.WriteLine(item.Name);
        }
    }
}

public class MyCustomObject
{
    // Note: You may want to use a type converter to convert the ID to an integer.
    public string ID { get; set; }
    public string Name { get; set; }
    public string Lastname { get; set; }
    public string Phone { get; set; }
    public string Mail { get; set; }
    public string Website { get; set; }

    public override string ToString()
    {
        return Name.ToString();
    }
}

public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject>
{
    public MyCustomObjectMap()
    {
        // In the name method, you provide the header text - i.e. the header value set in the first line of the CSV file.
        Map(m => m.ID).Name("id");
        Map(m => m.Name).Name("name");
        Map(m => m.Lastname).Name("lastname");
        Map(m => m.Phone).Name("phone");
        Map(m => m.Mail).Name("mail");
        Map(m => m.Website).Name("website");
    }
}

Some more details in an answer here.

Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
0

To skip the first line, just replace the line:

if (count == id)

with

if (count > 0 && count == id)

MORE THOUGHTS ON YOUR APPROACH

Because you used the ref keyword, each line you read will override the previous values you stored in the parameters. A better way to do this is to create a class to hold all the properties of interest. Then, for each line you read, package an instance of the class and add it to a list. You method signature (even the return type) will change eventually.

From your code, the class will look like this:

public class DataModel
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public string Phone{ get; set; }
    public string Mail { get; set; }
    public string Website{ get; set; }
}

Then your method will be like this:

public IList<DataModel> ReadEntrie(int id, string data_path)
{
    int count = 0;
    CreateConfigFile();
    var fs = new FileStream(data_path, FileMode.Open);
    var sr = new StreamReader(fs);
    try
    {
        var list = new List<DataModel>();
        string temp = "";
        bool cond = true;
        while (cond == true)
        {
            if ((temp = sr.ReadLine()) == null)
            {
                cond = false;
                if (count == 0)
                    throw new Exception("Failed");
            }
            if (count > 0 && count == id)
            {
                string[] stringSplit = temp.Split(',');
                var item = new DataModel();
                item.Name = stringSplit[0].Trim('"');
                item.LastName = stringSplit[1].Trim('"');
                item.Phone = stringSplit[2].Trim('"');
                item.Mail = stringSplit[3].Trim('"');
                item.Website = stringSplit[4].Trim('"');
                // add item to list
                list.Add(item);
            }
            count++;
        }
        return list;
    }
    catch
    {
        throw; // or do whatever you wish
    }
    finally
    {
        sr.Close();
        fs.Close();
    }
}
Soma Mbadiwe
  • 1,594
  • 16
  • 15
  • Thanks for the the quick response.I will try it. – Sam Jun 03 '17 at 03:40
  • Test run was done. It works but new problem start shinning a logic error. I cannot add new line for the new data, It always overwriting the 2nd line. – Sam Jun 03 '17 at 03:46
  • 1
    @Sam Your problem is due to your use of `ref`; every time your code runs, it overrides the previous data set. I will update my answer to show you a better way to go about it. – Soma Mbadiwe Jun 03 '17 at 03:58
  • I try your method above. But I encountered an error: Inconsistent accessiblity: return type 'IList' is less accessible than method 'csvfile.ReadEntrie(int, string)' – Sam Jun 03 '17 at 06:13
  • I used two class. To make a whole picture of my code processes. My research about ADD,UPDATE,EDIT,DELETE in the csv file, I refer to this link. And I debug for my specific used. I feel difficulties from this flow of codes..https://social.msdn.microsoft.com/Forums/en-US/27a98772-2dc6-4197-9f75-6cc119d4a88a/how-to-edit-a-line-from-a-text-file-using-c?forum=Vsexpressvcs – Sam Jun 03 '17 at 08:39
  • If you need help on doing CRUD operations on CSV files, you may want to ask a new question. My last comment solves the issue you reported: just mark the class `DataModel` as `public`. – Soma Mbadiwe Jun 03 '17 at 14:12