#c# #filehelpers
Вопрос:
Для контекста я пытаюсь проанализировать файл локализации 7dtd. Содержимое файла выглядит примерно так:
Key,File,Type,UsedInMainMenu,NoTranslate,english,Context / Alternate Text,german,latam,french,italian,japanese,koreana,polish,brazilian,russian,turkish,schinese,tchinese,spanish
meleeToolCrowbar,items,Tool,,,Crowbar,,,,,,,,,,,,,,
Проблема в том, что порядок представленных данных варьируется от файла к файлу, где в 1-й строке указывается размещение элементов для каждой записи в файле. Мне нужно прочитать этот файл и объединить его с несколькими другими файлами аналогичной конструкции.
Сначала я пытался просто прочитать и использовать разделенную строку на запятую для анализа, но, увы, в некоторых полях могут быть запятые (ограниченные кавычками). Поэтому, когда я начал исследовать потенциальные решения, появились файлообменники. Однако, из того, что я могу сказать, это использует статический столбец для определения свойств, и это не будет работать для моего контекста, поскольку а) порядок столбцов варьируется и б) присутствуют не все столбцы.
Любая помощь в поиске решения была бы очень признательна.
Комментарии:
1. Затем прочитайте файл, используя специальную библиотеку CSV; например, с помощью CSVHelper вы просто определяете класс со свойствами, которые вы хотите получить из файла, а затем указываете ему прочитать файл. Порядок столбцов не имеет значения. Прочтите это: joshclose.github.io/CsvHelper/getting-started/… — не изобретайте что-то новое, что не нуждается в изобретении (в миллионный раз)
2. Из того, что я вижу, это тоже не сработает, поскольку вы определяете свойство в классе, а затем связываете его с записью в столбце файла. Это не сработает, так как точно неизвестно, сколько столбцов и каков будет порядок столбцов.
3. Честно говоря, я бы не рекомендовал это, если бы не думал, что это сработает. Прямо сейчас передо мной открыт проект, который использует CSVH для чтения файла из полумиллиона строк и 37 столбцов, но меня интересуют только 7 из них. Свойства C# даже не имеют того же имени, что и заголовки;в большинстве заголовков есть пробелы, поэтому атрибуты используются для сопоставления, например, столбца «Код продукта» файла с моим свойством ProdCode
Ответ №1:
Если вы просмотрите часть библиотеки dynamic ClassBuilder, вы можете создать класс, который сопоставляется между столбцами и нужным классом, добавив поля. Затем используйте объект CreateRecordClass для создания фактического типа класса, который будет использоваться механизмом выполнения.
Это более сложно с помощью FileHelpers, чем, скажем, с помощью CSVHelper, где вы создаете сопоставление простым способом. Если вы используете CsvDataReader, то вы используете ClassMap для перехода между заголовками столбцов и свойствами, даже указывая конкретные индексы для столбцов, которые вам действительно нужны.
void Main()
{
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false,
};
using (var reader = new StreamReader("path\to\file.csv"))
using (var csv = new CsvReader(reader, config))
{
csv.Context.RegisterClassMap<FooMap>();
csv.Context.RegisterClassMap<BarMap>();
var fooRecords = new List<Foo>();
var barRecords = new List<Bar>();
while (csv.Read())
{
switch (csv.GetField(0))
{
case "A":
fooRecords.Add(csv.GetRecord<Foo>());
break;
case "B":
barRecords.Add(csv.GetRecord<Bar>());
break;
default:
throw new InvalidOperationException("Unknown record type.");
}
}
}
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Bar
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public sealed class FooMap : ClassMap<Foo>
{
public FooMap()
{
Map(m => m.Id).Index(1);
Map(m => m.Name).Index(2);
}
}
public sealed class BarMap : ClassMap<Bar>
{
public BarMap()
{
Map(m => m.Id).Index(1);
Map(m => m.Name).Index(2);
}
}