Я обрабатываю необработанные данные переписи населения США в базе данных SQL Server. Разархивированный файл tar дает чуть более 14 000 CSV-файлов, которые необходимо обработать в 266 различных таблицах базы данных. Мне нужно перебрать каждый CSV-файл и добавить к нему заголовок, чтобы SSIS мог вытянуть необработанные данные в целевую таблицу SQL Server.
Первые 6 столбцов каждого файла CSV абсолютно одинаковы. Остальные столбцы для файла отличаются. Данные в остальных столбцах в основном представляют собой числовые значения (целые и десятичные числа). Тем не менее, Бюро переписей добавляет символы, называемые значениями «jam», показывающие, почему нет значения. Мне нужно заменить эти значения jam на пустую или пустую строку, потому что столбцы таблицы целевой базы данных - DECIMALS, а значения jam приводят к сбою вставки в SSIS.
Итак, у меня есть библиотека классов C # (DotNet Core), зацикливающаяся на 14K-файлы. Для каждого файла я должен сделать следующее:
- создать переменную StringBuilder
- добавить заголовок строки в StringBuilder, чтобы SSIS работал
- цикл над каждой строкой в файле
- для каждой строки, я должен разделить первые 6 столбцов, потому что мне нужны эти строки в целевой таблице. Затем я разделяю оставшиеся столбцы, потому что мне нужно удалить значения пробок, оставляя числовые данные
- объединить первые 6 столбцов и убрать данные обратно в строку
- добавить недавно очищенную строку в StringBuilder
- после завершения цикла по всем строкам запишите StringBuilder в целевую папку, где SSIS будет загружаться в базу данных.
У меня есть 3 вложенных цикла:
- цикл более 14000 файлов
- для каждого файла, цикл по каждой строке
- для каждой строки, цикл по столбцам, удаляя символы
Вот мой код для зацикливания каждого файла:
private static Boolean BuildCensusDataFileWithHeader(String censusDataFilePath, String rowHeader, String censusDataDestinationFilePath)
{
try
{
// BUILD NEW FILE WITH HEADER
StringBuilder currentContent = new StringBuilder();
currentContent.Append(rowHeader + Environment.NewLine);
//RETRIEVE ALL LINES IN TARGET FILE
List<String> rawList = File.ReadAllLines(censusDataFilePath).ToList();
// LOOP THROUGH EACH LINE AND REMOVE ANY STRINGS IN COLUMNS AFTER COLUMN 6
// NOTE: COLUMNS 1-6 CONTAINS STRINGS NEEDED IN DATABASE
foreach (var row in rawList)
{
//TURN COMMA DELIMITED ROW OF DATA INTO ARRAY
String[] rowArray = row.Split(",");
// PEEL OFF FIRST 6 COLUMNS TO BE KEPT AS IS
IList<String> goodStrings = rowArray.Take(6).ToList();
// RETRIEVE REMAINING COLUMNS TO BE CLEANED OF STRINGS
IList<String> stringsToNullList = rowArray.Skip(6).ToList();
// REMOVE ALL STRINGS
stringsToNullList.OnlyDecimalValues();
// PUT GOOD COLUMNS AND CLEANED COLUMNS BACK TOGETHER AS A ROW
var cleanedRow = $"{String.Join(",", goodStrings)},{String.Join(",", stringsToNullList)}";
// APPEND ROW TO NEW DOCUMENT TO BE WRITTEN TO TARGET DIRECTORRY CONTAINING CLEANED DATA
currentContent.Append(cleanedRow + Environment.NewLine);
}
File.WriteAllText(censusDataDestinationFilePath, currentContent.ToString());
return true;
}
catch (Exception ee)
{
string temp = ee.Message;
return false;
}
}
Вот мои методы расширения, заменяющие символы пустым пространством:
public static void OnlyDecimalValues(this IList<String> stringToClean)
{
for (int i = 0; i < stringToClean.Count; ++i)
{
stringToClean[i] = (stringToClean[i].IsDecimal()) ? stringToClean[i] : "";
}
}
public static bool IsDecimal(this string text)
{
decimal test;
return decimal.TryParse(text, out test);
}
Это все работает через программирование методом грубой силы. Есть ли более эффективный способ сделать это?
Спасибо за ваше время.