2016-08-11 2 views
0

면책 조항에 정수와 같은 문자열을 주조 : 이것은 내가 MSSQL에 CSV를 가져올 시도하지만 위생을 위해 먼저 CSV 값을 반복 할 필요가 있어요 내 첫 닷넷 C# 프로젝트는 .NET DataTable을

입니다. CSV의 일부 열은 정수가되며 (나중에 계산에 사용됩니다) 일부는 일반 varchar입니다.

위의 스크립트는 SQL이 정수로 문자열을 쓸 수 없을 때 내 응용 프로그램에서 나중에 예외를 throw하는 문자열로 DataTable의 모든 값 (행 열 값)을 강제로 나타냅니다.

여기 내 데이터 테이터를 생성하고 채우는 getCSVImport에 사용하는 방법입니다.

내가 생각하는 것은 값이 정수인지 확인한 다음 정수로 캐스팅하는 다른 조건을 추가하는 것입니다. PHP는 유형을 그렇게 강력하게 처리하지 않으므로이 유형이 새로운 것입니다.하지만 두려움이 있습니다. dataTable 내에서 값을 여러 유형으로 혼합 할 수 있는지 확실하지 않으므로 작동하지 않습니다.

제 질문은 다른 유형의 데이터 테이블에 다른 값을 갖는 방법이 있습니까? 내 코드는 전체 줄을 받아서 문자열로 쓰고 문자열이나 정수로 값을 지정해야합니다.

/* 
    * getCsvData() 
    * This method will create a datatable from the CSV file. We'll take the CSV file as is. 
    * and collect the data as needed: 
    * 
    * - Remove those original 4 lines (worthless info) 
    * - Line 5 starts with the headers, remove any of the brackets around the values 
    * - Iterate through the rest of the fields and sanitize them before we add it to the datatable 
    * 
    */ 

    private DataTable getCsvData(string csv_file_path) 
    { 
     // Create a new csvData tabletable object: 
     DataTable csvData = new DataTable(); 
     try 
     { 
      using (TextFieldParser csvReader = new TextFieldParser(csv_file_path)) 
      { 
       csvReader.SetDelimiters(new string[] { "," }); 
       csvReader.HasFieldsEnclosedInQuotes = true; 
       int row = 1; 
       while (!csvReader.EndOfData) 
       { 
        // Read the string and collect the row data 
        string[] rowData = csvReader.ReadFields(); 

        if (row <= 4) 
        { 
         // We want to start on row 5 as first rows are nonsense :) 
         // Incriment the row so that we can do our magic above 
         row++; 
         continue; 
        } if(row == 5) 
        { 
         // Row 5 is the headers, we need to sanitize and continue: 
         foreach (string column in rowData) 
         { 
          // Remove the [ ] from the values: 
          var col = column.Substring(1, column.Length - 2); 
          DataColumn datecolumn = new DataColumn(col); 
          datecolumn.AllowDBNull = true; 
          csvData.Columns.Add(datecolumn); 
         } 
         // Incriment the row so that we can do our magic above 
         row++; 
        } else 
        { 
         // These are all of the actual rows, sanitize and add the rows: 
         //Making empty value as null 
         for (int i = 0; i < rowData.Length; i++) 
         { 
          // First remove the brackets: 
          if (rowData[i].Substring(0,1) == "[") 
          { 
           rowData[i] = rowData[i].Substring(1, rowData[i].Length - 2); 
          } 
          // Set blank to null: 
          if (rowData[i] == "" || rowData[i] == "-") 
          { 
           rowData[i] = null; 
          } 

          // Lastly, we need to do some calculations: 

         } 
         // Add the sanitized row to the DataTable: 
         csvData.Rows.Add(rowData); 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Could not parse the CSV file: "+ ex.Message); 
     } 
     return csvData; 
    } 
+0

정확히 무엇입니까? – Kinetic

+1

문자열을 정수로 "캐스팅"할 수는 없지만이를 구문 분석 할 수는 있습니다. 'int.Parse' 또는'int.TryParse'를 살펴보십시오. – Kroltan

+0

csv 파일의 열이 숫자이고 텍스트가 미리 알 수 있습니까? 또는 실행 사이에 변경 될 수 있습니까? –

답변

0

당신은 INT에 문자열을 캐스팅 할 수 있습니다

int j; 
bool parsed=Int32.TryParse("-105", out j)) 

을 TryParse으로는 성공 여부를 확인할 수 있습니다.

그런 다음 테이블에 다시 저장하려면 문자열로 변환하십시오. 간단하게 할 수 있습니다 <variable>.ToString()

0

기본적으로 data columns are initialized to a string data type입니다.

유형을 지정할 수있는 과부하가 있으므로 시도해 보시기 바랍니다. 열은 미리 알고 있으므로 코드에서 쉽게 처리 할 수 ​​있습니다.

private DataColumn AddColumn(string columnName, Type columnType) 
{ 
    // Remove the [ ] from the values: 
    var col = column.Substring(1, columnName.Length - 2); 
    DataColumn dataColumn = new DataColumn(col, columnType); 
    dataColumn.AllowDBNull = true; 
    return dataColumn; 
} 

if (row == 5) 
{ 
    csvData.Columns.Add(AddColumn(rowData[0], typeof(string))); 
    csvData.Columns.Add(AddColumn(rowData[1], typeof(int))); 
    csvData.Columns.Add(AddColumn(rowData[2], typeof(DateTime))); 
    csvData.Columns.Add(AddColumn(rowData[3], typeof(string))); 
    // etc 
} 

나는 당신도 DataTable에 추가하기 전에 다른 값을 변환해야합니다 모르겠지만, 당신이 경우에, 많은 내장 타입은 DateTime.TryParseInt32.TryParseTryParse 방법을 가지고있다. 연속으로 각각을 호출 할 수 있으며 "시도"중 하나가 성공하면 유형을 알 수 있습니다.

또는 이전에 열 유형을 알고 있으므로 각 값을 전송할 수 있습니다.

csvData.Rows.Add(Convert.ToString(rowData[0]), 
       Convert.ToInt32(rowData[1]), 
       Convert.ToDateTime(rowData[2]), 
       Convert.ToString(rowData[3])); 
0

내가 * .TryParse(), 즉를 사용합니다 :

*A sample csv file with 
*some comment lines at top 
-- with different comment 
// comment strings. 
[charField],[dateField],[intField],[decimalField] 
"Sample char data 1",2016/1/2,123,123.45 
"Sample char data 2",,2,1.5 
"Sample char data 3",,3, 
"Sample char data 4",,, 
,,, 
"Sample char data 6",2016/2/29 10:20,10,20.5 

당신은 그 날짜, INT, 소수점 필드에 TryParse을 사용할 수 있습니다 :

void Main() 
{ 
    var myData = ReadMyCSV(@"c:\MyPath\MyFile.csv"); 
    // do whatever with myData 
} 

public IEnumerable<MyRow> ReadMyCSV(string fileName) 
{ 
    using (TextFieldParser tfp = new TextFieldParser(fileName)) 
    { 
     tfp.HasFieldsEnclosedInQuotes = true; 
     tfp.SetDelimiters(new string[] { "," }); 

     //tfp.CommentTokens = new string[] { "*","--","//" }; 
     // instead of using comment tokens we are going to skip 4 lines 
     for (int j = 0; j < 4; j++) 
     { 
      tfp.ReadLine(); 
     } 

     // header line. 
     tfp.ReadLine(); 

     DateTime dt; 
     int i; 
     decimal d; 

     while (!tfp.EndOfData) 
     { 
      var data = tfp.ReadFields(); 

      yield return new MyRow 
      { 
       MyCharData = data[0], 
       MyDateTime = DateTime.TryParse(data[1], out dt) ? dt : (DateTime?)null, 
       MyIntData = int.TryParse(data[2], out i) ? i : 0, 
       MyDecimal = decimal.TryParse(data[3], System.Globalization.NumberStyles.Any, null, out d) ? d : 0M 
      }; 
     } 
    } 
} 

public class MyRow 
{ 
    public string MyCharData { get; set; } 
    public int MyIntData { get; set; } 
    public DateTime? MyDateTime { get; set; } 
    public decimal MyDecimal { get; set; } 
} 

이 샘플 CSV로 다음과 같이로드 된 데이터를 더욱 위생적으로 처리 할 수 ​​있습니다.

myData.Where(d => d.MyIntData != 0); 

참고 : 원하는 경우 DataTable을 사용하지 않았습니다.MSSQL 로딩의 경우 중간 메모리 인 SQLite 인스턴스를 사용하여 위생 데이터를 저장 한 다음 SqlBulkCopy 클래스를 사용하여 MSSQL으로 푸시하는 것이 좋습니다. DataTable은 물론 옵션입니다 (유연성이 떨어지는 것 같아요).