2014-04-04 19 views
5

Đây là mã của tôi để lấy dữ liệu từ tệp phẳng và chèn vào SQL Server. Nó tạo ra một ngoại lệ (Index was outside the bounds of the array).Chỉ số nằm ngoài giới hạn của ngoại lệ mảng

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

Trả lời

2

Trường hợp ngoại lệ xảy ra vì một trong những đường dây của bạn có ít hơn ba yếu tố tách bằng dấu chấm phẩy. Mặc dù bạn khai báo Values dưới dạng mảng String của ba phần tử, ảnh hưởng đến biến đến kết quả của hàm String.Split() khiến cho không liên quan: mảng của bạn sẽ có độ dài bất kỳ mà mảng được trả lại có. Nếu nó ít hơn, mã của bạn chắc chắn sẽ thất bại.

Nếu nó không được phép xảy ra tôi đề nghị bạn làm một sự khẳng định trong mã của bạn để giúp bạn gỡ rối:

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

Như một mặt lưu ý, tôi nên đề cập đến thực hiện một loạt INSERT sẽ hiệu quả hơn. Ngoài ra cách bạn khai báo và sửa lại biến số cmd không hoàn toàn chính xác. Và cuối cùng, bạn nên gọi số String.Replace trên các giá trị của mình để đảm bảo mọi dấu nháy đơn được tăng gấp đôi. Nếu không mã của bạn sẽ được mở cho các cuộc tấn công SQL injection.

2

Một số chi tiết về cách mã của bạn là hành xử tại thời gian chạy:

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

Tương tự như cách các giá trị tiếp tục bị ghi đè, mà SqlCommand đó là tạo ra bên ngoài vòng lặp sẽ không bao giờ còn được sử dụng. Đó là an toàn để đặt cả hai tờ khai này bên trong vòng lặp thay thế. Đoạn mã sau thực hiện điều đó và cũng thêm một số lỗi kiểm tra để đảm bảo rằng một số giá trị có thể sử dụng được lấy ra từ dòng. Nó sẽ đơn giản bỏ qua bất kỳ dòng nào không đủ dài - nếu đó không phải là OK thì bạn có thể cần tạo một số mã xử lý lỗi phức tạp hơn của riêng bạn.

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

Như một lưu ý cuối cùng, mã trên có thể dễ bị tấn công nếu bạn đang sử dụng nó như một ứng dụng web. Hãy suy nghĩ về lệnh nào có thể được gửi đến máy chủ nếu bạn đang xử lý một tệp trông giống như sau:

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

Tùy chọn an toàn hơn là sử dụng truy vấn tham số, giúp bảo vệ chống lại loại tấn công này. Họ làm điều này bằng cách tách lệnh khỏi các đối số của nó, giúp bảo vệ bạn khỏi việc truyền các giá trị cho các đối số giống như mã SQL. Một ví dụ về cách thiết lập mọi thứ theo cách đó sẽ trông giống như thế này:

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 để đề cập đến SQL injection. Tuy nhiên, văn bản trong câu hỏi của OP được phân chia bằng dấu cách (không phải là dấu ngắt dòng như trong ví dụ của bạn), điều này làm cho các cuộc tấn công kiểu này trở nên khó khăn hơn nhiều. –

+0

Thực ra tôi tin rằng sẽ tốt hơn nếu OP thực hiện chèn hàng loạt thay thế. Tuy nhiên, +1 cho một câu trả lời rất chi tiết. – Crono

1

Hãy thử điều này.

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

Bạn có nghĩa là '> =', chắc chắn. –

+0

@MrLister thậm chí như vậy đó vẫn là lời khuyên xấu IMHO. Điều này sẽ chỉ lặng lẽ bỏ qua các dòng có ít hơn 4 giá trị thay vì đưa ra một đầu mối về tệp có thể bị hỏng hoặc một cái gì đó. Tôi nghĩ rằng nó an toàn để giả định rằng nó không nên xảy ra ở tất cả cho một dòng có ít hơn bốn giá trị phân cách dấu chấm phẩy. – Crono

+1

Đó là lý do tại sao có một phần khác. Bạn có thể thêm thông báo lỗi đó vào mệnh đề else. – MoraRockey

Các vấn đề liên quan