2016-08-11 18 views
0

免責聲明鑄造String作爲整數:這是我的第一個.NET C#項目在.NET DataTable中

我試圖導入CSV到MSSQL,但需要通過CSV值第一個迭代的消毒目的。 CSV中的一些列將是整數(稍後將用於計算),其中一些是常規的varchar。

上面的腳本似乎強制DataTable中的所有值(即行列值)作爲一個字符串,當SQL無法將字符串作爲整數寫入時,它將在稍後引發我的應用程序中的Exception。

這是我用於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之前,其他值轉換,但如果這樣做,很多內置的類型有TryParse方法,如DateTime.TryParseInt32.TryParse。你可以連續打電話給他們,並且其中一個「嘗試」成功,你就會知道你的類型。

另外,既然您事先知道列類型,您可以只投出每個值。

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

我會用* .TryParse(),即:有了這個樣本CSV:

*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 

你可能會在這些日期時間,整型,小數字段使用的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; } 
} 

我可以進一步消毒加載的數據,例如:

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

注意:我沒有使用DataTable,如果我願意,我可以使用它。對於MSSQL加載,我可能會使用中間內存中的SQLite實例來保存清理過的數據,然後使用SqlBulkCopy類推送到MSSQL。 DataTable當然是一個選項(我認爲它不太靈活)。