2014-04-04 20 views
5

Hier ist mein Code, um Daten aus einer flachen Datei zu erhalten und in SQL Server einzufügen. Es erzeugt eine Ausnahme (Index was outside the bounds of the array).Index war außerhalb der Grenzen der Array-Ausnahme

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();     
} 

Antwort

2

Die Ausnahme geschieht, weil einer Ihrer Leitungen weniger als drei Elemente hat mit einem Semikolon getrennt. Obwohl Sie Values als String Array von drei Elementen deklarieren, macht die Auswirkung der Variable auf das Ergebnis von String.Split() die Funktion irrelevant: Ihr Array wird die Länge haben, die das zurückgegebene Array hat. Wenn es weniger ist, wird Ihr Code definitiv fehlschlagen.

Wenn es nicht angenommen hat, passieren Ich schlage vor, Sie in Ihrem Code eine Behauptung tun Debuggen, Ihnen zu helfen:

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

Als Randbemerkung, sollte ich erwähnen, ein Batch INSERT machen wäre wesentlich effizienter. Auch Ihre Art, cmd Variable zu deklarieren und zu beeinflussen, ist nicht ganz korrekt. Und schließlich sollten Sie String.Replace auf Ihre Werte aufrufen, um sicherzustellen, dass alle Apostrophe verdoppelt werden. Andernfalls wird Ihr Code für SQL-Injection-Angriffe geöffnet.

2

Einige Details, wie Sie Ihren Code zur Laufzeit verhält:

// 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();     
} 

Ähnlich wie überschrieben hält Werte immer, dass SqlCommand, die außerhalb der Schleife auch gewöhnen wird erstellt nie. Es ist sicher, diese beiden Deklarationen stattdessen in die Schleife einzufügen. Der folgende Code tut das und fügt außerdem eine Fehlerüberprüfung hinzu, um sicherzustellen, dass eine verwendbare Anzahl von Werten aus der Zeile abgerufen wurde. Es werden einfach alle Zeilen übersprungen, die nicht lang genug sind - wenn das nicht in Ordnung ist, müssen Sie möglicherweise einen komplexeren eigenen Fehlerbehandlungscode erstellen.

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(); 
     } 
    } 
} 

Als eine letzte Anmerkung, könnte der obige Code anfällig für Hacker sein, wenn Sie es in so etwas wie eine Web-Anwendung verwendet haben. Überlegen Sie, was Befehl könnte an den Server gesendet bekommen, wenn Sie eine Datei wurden verarbeitet, die so aussah:

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

Eine sicherere Option ist parametrisierte Abfragen zu verwenden, die gegen diese Art von Angriffen schützen helfen. Sie tun dies, indem Sie den Befehl von seinen Argumenten trennen, was Sie vor der Übergabe von Werten für Argumente schützt, die wie SQL-Code aussehen. Ein Beispiel dafür, wie man die Dinge auf diese Weise einrichtet, sieht ungefähr so ​​aus:

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 für die Erwähnung der SQL-Injektion. Der Text in der OP-Frage wird jedoch durch Leerzeichen getrennt (nicht wie in Ihrem Beispiel durch Zeilenumbrüche), wodurch Angriffe dieser Art erheblich erschwert werden. –

+0

Eigentlich glaube ich, dass es für das OP besser wäre, stattdessen einen Stapel einzufügen. Trotzdem, +1 für eine sehr detaillierte Antwort. – Crono

1

Versuchen Sie dies.

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

Sie meinen '>' 'sicherlich. –

+0

@MrLister auch so, das ist immer noch ein schlechter Rat IMHO. Dies wird nur Zeilen mit weniger als 4 Werten überspringen, anstatt einen Hinweis darauf zu geben, dass die Datei möglicherweise beschädigt ist. Ich denke, man kann davon ausgehen, dass es überhaupt nicht vorkommen sollte, dass eine Zeile weniger als vier durch Semikolon getrennte Werte hat. – Crono

+1

Deshalb gibt es den anderen Teil. Sie können diese Fehlermeldung in der else-Klausel hinzufügen. – MoraRockey

Verwandte Themen