这是我从平面文件中获取数据并插入SQL Server的代码。它正在生成异常(Index was outside the bounds of the 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();
}
答案 0 :(得分:2)
发生异常是因为您的一行中少于三个元素以分号分隔。即使您将Values
声明为包含三个元素的String
数组,但影响变量到String.Split()
函数的结果会使其无关紧要:您的数组将具有返回数组所具有的任何长度。如果它更少,你的代码肯定会失败。
如果不应该发生这种情况,我建议你在代码中做一个断言来帮助你调试:
// ...
Values = line1.Split(';');
// the following will make the debugger stop execution if line.Length is smaller than 3
Debug.Assert(line1.Length >= 3);
// ...
作为旁注,我应该提一下,批处理INSERT
会更有效率。您声明和重新生成cmd
变量的方式也不太正确。最后,您应该在值上调用String.Replace
以确保任何撇号加倍。否则,您的代码将打开SQL注入攻击。
答案 1 :(得分:2)
有关代码在运行时的行为方式的一些详细信息:
// 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();
}
类似于值被覆盖的方式,在循环外创建的SqlCommand
也将永远不会被使用。将这两个声明放在循环中是安全的。下面的代码执行此操作,并添加了一些错误检查以确保从该行检索可用数量的值。它只会跳过任何不够长的行 - 如果不行,那么你可能需要创建一些更复杂的错误处理代码。
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();
}
}
}
最后要注意的是,如果你在像Web应用程序这样的东西中使用它,上面的代码可能容易受到黑客攻击。如果您正在处理如下所示的文件,请考虑可能将命令发送到服务器:
1;2;3
4;5;6
7;8;9') DROP TABLE demooo SELECT DATALENGTH('1
更安全的选择是使用参数化查询,这将有助于防止此类攻击。他们通过将命令与其参数分开来实现此目的,这有助于保护您不会传递看起来像SQL代码的参数的值。如何以这种方式设置的示例看起来更像是:
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();
}
答案 2 :(得分:1)
试试这个。
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();
}
}