У меня есть входной файл CSV:
|Name|Surname|Age|
|ABCD|DCBA|11|
|QAZ|WSX|23|
И когда я пытаюсь загрузить файл csv в свою таблицу datagridview, у меня первый столбец пуст, потому что функция считывает первый разделенный символ |.
Как пропустить первый разделенный символ в каждой строке?
Часть кода:
file.ReadLine();
string line = "";
try
{
while ((line = file.ReadLine()) != null)
{
string[] splitArray = line.Split('|');
Listing.Add(new List(splitArray[0], splitArray[1], splitArray[2]));
count++;
}
}
catch
{
MessageBox.Show("Nothing to do here...");
}
file.Close();
Может помочь метод String.Trim (char []). Вы можете указать массив символов, который следует обрезать от начала и до конца перед выполнением разделения. docs.microsoft.com/en-us/dotnet/api/…
@Dai Я добавил пример CsvHelper к своему ответу ниже.





Просто проигнорируйте первый индекс, используя splitArray[1], splitArray[2] и splitArray[3] (игнорируя splitArray[0]):
file.ReadLine();
string line = "";
try
{
while ((line = file.ReadLine()) != null)
{
string[] splitArray = line.Split('|');
Listing.Add(new List(splitArray[1], splitArray[2], splitArray[3]));
count++;
}
}
catch
{
MessageBox.Show("Nothing to do here...");
}
file.Close();
Как указывали другие, почему бы не использовать CsvHelper?
Вы можете сделать это с помощью довольно простой конфигурации:
public struct Listing
{
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
}
using (var file = File.OpenText("test.txt"))
{
using (var csv = new CsvHelper.CsvReader(file))
{
csv.Configuration.Delimiter = "|";
var records = csv.GetRecords<Listing>().ToList();
foreach (var record in records)
{
Console.WriteLine("Name: {0}, Surname: {1}, Age: {2}", record.Name, record.Surname, record.Age);
}
}
}
Здесь вы можете увидеть пример вывода:

Я бы избегал использования ToList, чтобы избежать ненужного выделения памяти, и использовать Skip (1) и Take (n), чтобы сделать решение более гибким, если OP требуется для внесения некоторых изменений в фрагмент.
Поскольку данные устанавливаются из файла, я бы реорганизовал ваше решение, чтобы вместо этого использовать структуру, потому что класс не имеет поведения, а вы просто представляете данные в файле. Рефакторинг должен сделать работу немного быстрее
@KevinAvignon Я всегда фанат классов, поскольку они обычно намного более расширяемы, так как он может захотеть добавить методы в будущем, такие как свойство FullName (но я обновил код). Что касается .ToList(), я знаю, что это вызовет полное перечисление, и я делаю это только потому, что Listings изначально был списком, и я не уверен, каков его план использования. Зачем мне использовать Skip(1) или Take(n)?
в выражении LINQ Skip показывает, что вы не один из первых элементов в итерации, а Take покажет, что вам понадобятся только следующие n элементов в итерации, а остальные не имеют отношения к текущему конвейеру.
Но нам нужен первый элемент в итерации? Я не понимаю, откуда это взялось. Вы пытаетесь сказать об оптимизации (т. Е. Если мы используем Skip(1), это не вызовет ненужного выделения структуры листинга, если я не использую .ToList())?
@KevinAvignon struct в C# имеет другую семантику типа значения по сравнению с class, что означает, что struct могут быть более дорогими во время выполнения, чем class, в зависимости от сценария использования, поэтому я не согласен с вашим советом. Кроме того, struct может иметь методы, реализовывать интерфейсы, быть изменяемым и т. д. - так что сказать, что «структура не имеет поведения», просто неверно.
@Dai для данного сценария, у него нет поведения, и просто наличие класса для этого набора данных не имело для меня смысла. Я знаю о различиях между классом и структурой. Но в этом случае я принимаю то, что ты сказал
@FrankerZ Я говорю, что это мог быть Listing.AddRange (splitArray.Skip (1) .Take (3)), и при итерации по записям вам не нужно выделять память перед повторением по ней, вы можете разрешить записи быть IEnumerable
Я на 100% согласен с вами, и в большинстве случаев я бы предпочел пойти с вами, но при использовании блока using() {}, если он вырывается из цикла (возможно, с оператором return в веб-API), IEnumerable терпит неудачу, поскольку файловый поток был закрыт. Это приводит к тому, что у большинства новых пользователей возникают небольшие проблемы, поэтому я предпочитаю просто использовать .ToList() для облегчения доступа в будущем (хотя это определенно может привести к потере памяти / производительности для больших наборов данных).
@FrankerZ ваше решение работает. Осталось только поменять индекс с 1 ... 3, а не с 0. Не знаю, почему раньше не проверял :) :) Спасибо большое.
Я настоятельно рекомендую вам изучить csvhelper @Frihu, так как он намного лучше и дает более чистый код. (Для этого вы должны создавать структуры / классы, а не просто использовать массив)
@FrankerZ, этот csvhelper будет более эффективным, чем этот обходной путь? Что со временем конвертации файлов csv будет меньше?
Вы можете передать дополнительный второй аргумент StringSplitOptions в RemoveEmptyEntries:
string[] splitArray = line.Split('|', StringSplitOptions.RemoveEmptyEntries);
(Не DV), но это может вызвать некоторые проблемы, если одно из полей действительно содержит пустую запись. (например, |ABCD||11|)
Избегайте использования
String.Splitдля анализа файлов, поскольку он прерывается, если значение содержит символ|. Подумайте об использовании хорошо протестированной библиотеки CSV, например nuget.org/packages/CsvHelper