Чтение CSV файла C#

Дата публикации: 11-07-2011 | Автор: MelfisFettel | Рубрика: C#

Visual C# ответыНедавно передо мной встала проблема. Нужно было сравнить 2 CSV файла, и найти различающиеся значения, выполнить изменения и сохранить новый CSV с исправленными данными. Мне это было нужно для сравнения прайс листов. То есть поиск изменений в ценах в исходном прайсе относительно прайса поставщика. Так как CSV обычный файл с текстом, работа со строками не составит ни какого труда. С начала хотел использовать для данной задачи Delphi, но, в конце концов решил использовать C#.

Итак. Для наглядности просто прочитаем CSV файл при помощи C#, и выведем данные в listView. Остальные процедуры сравнения, поиска, отбора и перезаписи думаю, вы сможете написать сами. Заранее скажу, что для сравнения значений достаточно двух вложенных циклов for.

00 CSV файл.

Итак. Создадим новый проект, и объявим новый класс Cargo, в котором объявим переменные для хранения наших данных. Так как формат CSV файла заранее известен, создадим столько переменных сколько «столбцов» в нашем файле. Далее будем работать с CSV вот такого вида.

«id»,»Наименование»,»ЦенаПоставщика»,»НашаЦена»
1,»Товар 1″,100,120
2,»Товар 2″,120,135
3,»Товар 3″,450,490
4,»Товар 4″,80,100
5,»Товар 5″,3200,3380

01 Объявление нового класса

Для начала подключите:
using System.IO;
Итак, объявим новый класс:

1
2
3
4
5
6
7
public class Cargo
        {
            public string ID { get; set; }
            public string Name { get; set; }
            public string List_price { get; set; }
            public string MyPrice { get; set; }
        }
public class Cargo
        {
            public string ID { get; set; }
            public string Name { get; set; }
            public string List_price { get; set; }
            public string MyPrice { get; set; }
        }

02 Делим строку на части

Теперь объявим новый метод который будет получать строку нашего файла и записывать данные в структуру разбив ее на части согласно разделителю:

1
2
3
4
5
6
7
8
public void piece (string line)
            {
                string[] parts = line.Split('%');  //Разделитель в CSV файле.
                ID = parts[0];
                Name = parts[1];
                List_price = parts[2];
                MyPrice = parts[3];
            }
public void piece (string line)
            {
                string[] parts = line.Split('%');  //Разделитель в CSV файле.
                ID = parts[0];
                Name = parts[1];
                List_price = parts[2];
                MyPrice = parts[3];
            }

03 Получение строк из CSV файла

Последним методом нашего класса будет метод для чтения CSV файла, который будет читать строку и предавать ее методу piece() и возваращать в структуру типа List, с которой мы и будем дальше работать:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
            public static List<Cargo> ReadFile(string filename)
            {
                List<Cargo> res = new List<Cargo>();
                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        Cargo p = new Cargo();
                        p. piece (line);
                        res.Add(p);
                    }
                }
 
                return res;
            }
            public static List<Cargo> ReadFile(string filename)
            {
                List<Cargo> res = new List<Cargo>();
                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        Cargo p = new Cargo();
                        p. piece (line);
                        res.Add(p);
                    }
                }

                return res;
            }

04 Общий вид класса

Итак вот что у меня получилось:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        //Класс для получения данных из CVS файла
        public class Cargo
        {
            public string ID { get; set; }
            public string Name { get; set; }
            public string List_price { get; set; }
            public string MyPrice { get; set; }
 
            public void piece(string line)
            {
                string[] parts = line.Split(',');  //Разделитель в CVS файле.
                ID = parts[0];
                Name = parts[1];
                List_price = parts[2];
                MyPrice = parts[3];
            }
 
 
 
            public static List<Cargo> ReadFile(string filename)
            {
                List<Cargo> res = new List<Cargo>();
                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        Cargo p = new Cargo();
                        p.piece(line);
                        res.Add(p);
                    }
                }
 
                return res;
            }
        }
        //Класс для получения данных из CVS файла
        public class Cargo
        {
            public string ID { get; set; }
            public string Name { get; set; }
            public string List_price { get; set; }
            public string MyPrice { get; set; }

            public void piece(string line)
            {
                string[] parts = line.Split(',');  //Разделитель в CVS файле.
                ID = parts[0];
                Name = parts[1];
                List_price = parts[2];
                MyPrice = parts[3];
            }



            public static List<Cargo> ReadFile(string filename)
            {
                List<Cargo> res = new List<Cargo>();
                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        Cargo p = new Cargo();
                        p.piece(line);
                        res.Add(p);
                    }
                }

                return res;
            }
        }

05 Подготавливаем форму

Создадим на форме новый объект типа listView1 и одну кнопку Button, и выставим в ListView следующие параметры:

View: Details
GridLines: true

Создадим четыре колонки для отображения данных в нашем ListView:

ID
Наименование
Цена поставщика
Конечная цена

Вот что у меня вышло:

Чтение CSV файла на C#

06 Работа программы

Теперь на событие Click кнопки button1 пишем следующий код:

1
2
3
4
5
6
7
8
9
10
11
12
//Создаем новый экземпляр
List<Cargo> CSV_Struct = new List<Cargo>();
CSV_Struct = Cargo.ReadFile("ПУТЬ К ФАЙЛУ");
 
//Заполняем listView из нашей структуры
for (int i = 0; i <= CSV_Struct.Count-1; i++)
    {
    listView1.Items.Add(CSV_Struct[i].ID);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].Name);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].List_price);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].MyPrice);
    }
//Создаем новый экземпляр
List<Cargo> CSV_Struct = new List<Cargo>();
CSV_Struct = Cargo.ReadFile("ПУТЬ К ФАЙЛУ");

//Заполняем listView из нашей структуры
for (int i = 0; i <= CSV_Struct.Count-1; i++)
    {
    listView1.Items.Add(CSV_Struct[i].ID);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].Name);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].List_price);
    listView1.Items[i].SubItems.Add(CSV_Struct[i].MyPrice);
    }

И вот результат:

Чтение CSV файла в ListView C#

Для того что бы сравнить 2 файла нужно всего лишь создать два экземпляра List и загрузить в них разные файлы и сравнивать значения через вложенный цикл for.

Готовый проект можно скачать тут.

Понравилась статья? Расскажи друзьям:


Комментариев (16)

подскажите, как будет выглядеть метод чтения одной строки из cav файла?

*csv файла*

Обратите внимание вот на этот метод public static List ReadFile(string filename)
{
List res = new List();
using (StreamReader sr = new StreamReader(filename))
{
string line;
while ((line = sr.ReadLine()) != null)
{
Cargo p = new Cargo();
p. piece (line);
res.Add(p);
}
}

return res;
} .

Файл читается пока while ((line = sr.ReadLine()) != null).
Что бы прочитать одну строку файла достаточно будет вызвать этот же метод без while. То есть
line = sr.ReadLine()
Cargo p = new Cargo();
p. piece (line);
res.Add(p);

Подскажите а как сделать что бы потом создать SQL запрос, что бы можно было отправить в базу данных?

Сам запрос напишите исходя из ваших данных. Недавно писал «парсер» для сравнениф 2х CSV файлов и обновления прайса для 1С Битрикс. Использовал вот так:
DbConnection dbConnection = new SqlConnection(«Строка Вашего подключения к БД»);
dbConnection.Open();
DbCommand cmd = dbConnection.CreateCommand();
cmd.CommandText = string.Format(«SQL ЗАПРОС)», tableName, columns, values);
cmd.ExecuteNonQuery();
dbConnection.Close();

Спасибо, автор молодец!

Почему вы метод ReadFile() сделали статическим?

Наверное по тому что у каждого свой путь, свои грабли и свои ошибки. Я не претендую на 100% правильность с точки зрения конкретного языка программирования. Это мой пример и опыт, и не более того. Использовать его или нет решать каждому самостоятельно. Но все же наверно это все отговорки. На самом деле программирование на C# на данный момент для меня является не более чем хобби, в свободное от работы время. Если Вы что то хотите дополнить и поправить, я с удовольствием внесу Ваши поправки и комментарии в виде сноски к статье, с указанием автора и его контактных данных.

Потому, что если его не сделать статическим, то вот здесь:

/*Вот в этом месте,придётся создавать новый объект класса Cargo, который в данном варианте решения, будет занимать ресурс, исключительно для того, чтобы обратиться к этому методу,что не вполне рационально,в то время как к статическому методу класса, можно обратиться напрямую, не создавая отдельный экземпляр*/

/*Создаем новый экземпляр без статического метода ReadFile();*/

Cargo nafigNado = new Cargo();
List CSV_Struct = new List();
CSV_Struct = Cargo.ReadFile(«ПУТЬ К ФАЙЛУ»);

Подскажите пожалуйста как можно сделать кнопки Сохранить и Открыть с возможностью выбора в listView?

Используйте стандартные диалоги из VCL, и на обработчик клика вашего меню в listView повесьте вызов нужного вам диалога.

Ошибка «Индекс находился вне границ массива».

не подскажите, почему у меня знаки вопросов, вместо букв и цифр?

StreamReader sr = new StreamReader(filename, Encoding.Default)
или Encoding.UTF8 или любую другую, в которой записан Ваш файл

огромное спасибо)

Примитив для лабораторной работы — не более

Если в текстовом «поле» вдруг встретится разделитель, то вся эта система рухнет.

Обсудить