2014-04-04 14 views
5

Ecco il mio codice per ottenere dati da un file flat e inserirli in SQL Server. Sta generando un'eccezione (Index was outside the bounds of the array).L'indice era fuori dai limiti dell'eccezione dell'array

string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName);      
string text = System.IO.File.ReadAllText(path);    
string[] lines = text.Split(' ');         
con.Open();     
SqlCommand cmd = new SqlCommand();     
string[] Values = new string[3];         
foreach (string line1 in lines)     
{      
    Values = line1.Split(';');           
    string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";      
    cmd = new SqlCommand(query,con);      
    cmd.ExecuteNonQuery();     
} 

risposta

2

L'eccezione accade perché una delle linee ha meno di tre elementi separati con una virgola. Anche se dichiarate come un array String di tre elementi, il che influenza la variabile sul risultato della funzione String.Split() rende irrilevante: l'array avrà la lunghezza della matrice restituita. Se è inferiore, il tuo codice fallirà sicuramente.

Se non suppone accada ti suggerisco di fare un'affermazione nel codice per aiutare il debug:

// ... 
Values = line1.Split(';'); 
// the following will make the debugger stop execution if line.Length is smaller than 3 
Debug.Assert(line1.Length >= 3); 
// ... 

Come nota a margine, vorrei ricordare facendo una partita INSERT sarebbe molto più efficiente. Anche il tuo modo di dichiarare e riproporre la variabile cmd non è del tutto corretto. E infine dovresti chiamare String.Replace sui tuoi valori per assicurarti che gli apostrofi siano raddoppiati. In caso contrario, il codice sarà aperto per gli attacchi di SQL injection.

2

alcuni dettagli su come il codice si comporta in fase di esecuzione:

// This line declares a variable named Values and sets its value to 
// a new array of strings. However, this new array is never used 
// because the loop overwrites Values with a new array before doing 
// anything else with it. 
string[] Values = new string[3];         
foreach (string line1 in lines)     
{      
    Values = line1.Split(';');   
// At this point in the code, whatever was previously stored in Values has been 
// tossed on the garbage heap, and Values now contains a brand new array containing 
// the results of splitting line1 on semicolons. 
// That means that it is no longer safe to assume how many elements the Values array has. 
// For example, if line1 is blank (which often happens at the end of a text file), then 
// Values will be an empty array, and trying to get anything out of it will throw an 
// exception         
    string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";      
    cmd = new SqlCommand(query,con);      
    cmd.ExecuteNonQuery();     
} 

Simile a come Valori mantiene sempre sovrascritti, che SqlCommand che si crea al di fuori del ciclo sarà anche mai abituarsi. È sicuro inserire entrambe le dichiarazioni all'interno del ciclo. Il seguente codice lo fa, e aggiunge anche qualche controllo degli errori per assicurarsi che un numero utilizzabile di valori sia stato recuperato dalla linea. Salterà semplicemente le righe che non sono abbastanza lunghe - se ciò non va bene, potrebbe essere necessario creare un codice di gestione degli errori più complesso.

foreach(string line in lines) 
{ 
    string[] values = line.split[';']; 
    if(values.Length >= 3) 
    { 
     string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')";  
     using (SqlCommand command = new SqlCommand(query, con)) 
     { 
      cmd.ExecuteNonQuery(); 
     } 
    } 
} 

Come una nota finale, il codice di cui sopra potrebbe essere vulnerabile agli hacker se si sta utilizzando in qualcosa di simile a un'applicazione Web. Pensate a cosa potrebbe avere il comando inviato al server se si stesse elaborando un file che si presentava così:

1;2;3 
4;5;6 
7;8;9') DROP TABLE demooo SELECT DATALENGTH('1  

Un'opzione più sicura è quella di utilizzare query con parametri, che vi aiuterà a proteggere contro questo tipo di attacco. Lo fanno separando il comando dai suoi argomenti, che aiuta a proteggerti dal passare in valori per argomenti che assomigliano al codice SQL. Un esempio di come impostare le cose in questo modo sarebbe più simile a questo:

string query = "INSERT INTO demooo VALUES (@val1, @val2, @val3); 
using (var command = new SqlCommand(query, con)) 
{ 
    command.Parameters.AddWithValue("@val1", Values[0]); 
    command.Parameters.AddWithValue("@val2", Values[1]); 
    command.Parameters.AddWithValue("@val3", Values[2]); 
    command.ExecuteNonQuery(); 
} 
+0

+1 per menzionare l'iniezione SQL. Tuttavia, il testo nella domanda dell'OP è diviso per spazi (non per le interruzioni di riga come nel tuo esempio), il che rende gli attacchi di questo tipo molto più difficili. –

+0

In realtà credo che sarebbe meglio per l'OP fare un inserto batch. Ancora, +1 per una risposta molto ben dettagliata. – Crono

1

Prova questa.

string path = string.Concat(Server.MapPath("~/TempFiles/"), Fileupload1.FileName); 
string text = System.IO.File.ReadAllText(path); 
string[] lines = text.Split(' '); 
con.Open(); 
string[] Values; 
foreach (string line1 in lines) 
{ 
    Values = line1.Split(';'); 

    if (Values.Length >= 3) 
    { 
     string query = "INSERT INTO demooo VALUES ('" + Values[0] + "','" + Values[1] + "','" + Values[2] + "')"; 
    } 
    else 
    { 
     //Some error occured 
    } 

    using (var cmd = new SqlCommand(query,con)) 
    { 
     cmd.ExecuteNonQuery(); 
    } 
} 
+1

Vuoi dire '> =', sicuramente. –

+0

@MrLister anche se questo è ancora un cattivo consiglio IMHO. Questo salterà silenziosamente le linee con meno di 4 valori piuttosto che dare l'idea che il file potrebbe essere corrotto o qualcosa del genere. Penso che sia lecito supporre che non dovrebbe accadere affatto che una linea abbia meno di quattro valori separati da punto e virgola. – Crono

+1

Ecco perché c'è la parte else. È possibile aggiungere tale messaggio di errore nella clausola else. – MoraRockey

Problemi correlati