foreach (string file in files)
{
//把要执行的SQL保存到数组,然后用事务一起提交
List<string> sqlList = new List<string>();
List<MySqlParameter[]> paraList = new List<MySqlParameter[]>();
using (StreamReader reader = new StreamReader(file))
{
//计数器,5万条写一次数据库
int dataNum = 0;
while ((line = reader.ReadLine()) != null)
{
sqlList.Add(str);
paraList.Add(cmdParms);
dataNum++;
//5万条保存一次数据库
if (dataNum == 50000)
{
ExecuteTransaction(sqlList, paraList);
dataNum = 0;
sqlList.Clear();
paraList.Clear();
}
}
//保存订单到数据库
DBHelper.ExecuteTransaction(sqlList, paraList);
}
15 个解决方案
#1
一次性都读进去 应该会很慢 ,可以试试每次读100M 。
个人理解。
个人理解。
#2
使用多线程或者并行编程,让读取操作放在后台进行,你不要一次性读取所有数据到内存中,应该设置个缓存
#3
请问,有这方面的例子么
#4
这么大的文件读取加载本身就是个问题,建议试试多线程
#5
多线程也需要内存的吧。 我们服务器内存太少了
#6
这个例子希望对你有所帮助。这个程序处理的大批量txt数据,进行处理后批量导入到数据库中,时间方面还是不错的,没有卡死等现象出现。关键是BatchSize方法的设置,一定小心,否则就出现你的情况。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace bulkdata
{
class Program
{
static void Main(string[] args)
{
string[] directoy = Directory.GetFiles(@"E:\工作\巡检分析\txt数据\3月\下");//存放了状态数据文件夹下的所有文件夹
for (int di = 0; di < directoy.Length; di++)
{
StreamReader sr = new StreamReader(directoy[di],System.Text.Encoding.Default);//最为常用的打开txt,设定编码方式
DataTable dt = new DataTable();//创建表
//添加表头
DataColumn a = new DataColumn("time", Type.GetType("System.DateTime"));
DataColumn b = new DataColumn("name", Type.GetType("System.String"));
DataColumn j = new DataColumn("type", Type.GetType("System.Char"));
DataColumn c = new DataColumn("rost", Type.GetType("System.Int32"));
DataColumn d = new DataColumn("threshold", Type.GetType("System.Int32"));
DataColumn e = new DataColumn("tcr", Type.GetType("System.Single"));
DataColumn f = new DataColumn("longitude", Type.GetType("System.Single"));
DataColumn g = new DataColumn("latitude", Type.GetType("System.Single"));
DataColumn h = new DataColumn("dop", Type.GetType("System.Single"));
DataColumn i = new DataColumn("fe", Type.GetType("System.Int32"));
dt.Columns.Add(a); dt.Columns.Add(b); dt.Columns.Add(c); dt.Columns.Add(d); dt.Columns.Add(e);
dt.Columns.Add(f); dt.Columns.Add(g); dt.Columns.Add(h); dt.Columns.Add(i); dt.Columns.Add(j);
String line;
while ((line = sr.ReadLine()) != null)
{
try
{
string[] splits = line.Split(new Char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries);//用' ', ' '分开
splits[0] = splits[0] + " " + splits[1];
char stype = getstationtype(splits[2]);
string sname = getstationname(splits[2]);
DateTime stime = DateTime.Parse(splits[0]);
if ((stime > DateTime.Parse("9999-12-31 11:59:59")) || (stime < DateTime.Parse("1753-1-1 12:00:00")))
{
continue;
}
DataRow dr = dt.NewRow();//添加行数据
dr["time"] = DateTime.Parse(splits[0]);
dr["name"] = sname;
dr["type"] = stype;
dr["rost"] = Convert.ToInt32(splits[3]);
dr["threshold"] = Convert.ToInt32(splits[4]);
dr["tcr"] = Convert.ToSingle(splits[5]);
dr["longitude"] = Convert.ToSingle(splits[6]);
dr["latitude"] = Convert.ToSingle(splits[7]);
dr["dop"] = Convert.ToSingle(splits[8]);
dr["fe"] = Convert.ToInt32(splits[9]);
dt.Rows.Add(dr);
}
catch
{
continue;
}
}
sr.Close();
if(dt!=null)
AddDataByLocal(dt); //批量插入
Console.WriteLine(directoy[di].ToString());
}
}
public static bool AddDataByLocal(DataTable dt)
{
bool result = false;
string constring = @"server=.\sqlexpress;integrated security=true;database=status201303";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(constring))
{
conn.Open();
try
{
using (System.Data.SqlClient.SqlBulkCopy sbc = new System.Data.SqlClient.SqlBulkCopy(constring))
{
try
{
sbc.DestinationTableName = "Late"; //服务器上目标表的名称
sbc.BatchSize = 1000;//很重要,否则会报时间超时的错误
sbc.BulkCopyTimeout = 1000;//设置允许超时时间为100秒
sbc.ColumnMappings.Add("time", "time"); //本地表和目标表列名
sbc.ColumnMappings.Add("name", "name");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("type", "type");
sbc.ColumnMappings.Add("rost", "rost"); //本地表和目标表列名
sbc.ColumnMappings.Add("threshold", "threshold");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("tcr", "tcr"); //本地表和目标表列名
sbc.ColumnMappings.Add("longitude", "longitude"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("latitude", "latitude"); //本地表和目标表列名
sbc.ColumnMappings.Add("dop", "dop"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("fe", "fe"); //如果表有多个字段,下面继续添加
sbc.WriteToServer(dt);//插入数据
result = true;
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
return result;
}
public static char getstationtype(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return 'B';
else
return 'A';
}
public static string getstationname(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return s.TrimEnd('B');
else
return s;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace bulkdata
{
class Program
{
static void Main(string[] args)
{
string[] directoy = Directory.GetFiles(@"E:\工作\巡检分析\txt数据\3月\下");//存放了状态数据文件夹下的所有文件夹
for (int di = 0; di < directoy.Length; di++)
{
StreamReader sr = new StreamReader(directoy[di],System.Text.Encoding.Default);//最为常用的打开txt,设定编码方式
DataTable dt = new DataTable();//创建表
//添加表头
DataColumn a = new DataColumn("time", Type.GetType("System.DateTime"));
DataColumn b = new DataColumn("name", Type.GetType("System.String"));
DataColumn j = new DataColumn("type", Type.GetType("System.Char"));
DataColumn c = new DataColumn("rost", Type.GetType("System.Int32"));
DataColumn d = new DataColumn("threshold", Type.GetType("System.Int32"));
DataColumn e = new DataColumn("tcr", Type.GetType("System.Single"));
DataColumn f = new DataColumn("longitude", Type.GetType("System.Single"));
DataColumn g = new DataColumn("latitude", Type.GetType("System.Single"));
DataColumn h = new DataColumn("dop", Type.GetType("System.Single"));
DataColumn i = new DataColumn("fe", Type.GetType("System.Int32"));
dt.Columns.Add(a); dt.Columns.Add(b); dt.Columns.Add(c); dt.Columns.Add(d); dt.Columns.Add(e);
dt.Columns.Add(f); dt.Columns.Add(g); dt.Columns.Add(h); dt.Columns.Add(i); dt.Columns.Add(j);
String line;
while ((line = sr.ReadLine()) != null)
{
try
{
string[] splits = line.Split(new Char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries);//用' ', ' '分开
splits[0] = splits[0] + " " + splits[1];
char stype = getstationtype(splits[2]);
string sname = getstationname(splits[2]);
DateTime stime = DateTime.Parse(splits[0]);
if ((stime > DateTime.Parse("9999-12-31 11:59:59")) || (stime < DateTime.Parse("1753-1-1 12:00:00")))
{
continue;
}
DataRow dr = dt.NewRow();//添加行数据
dr["time"] = DateTime.Parse(splits[0]);
dr["name"] = sname;
dr["type"] = stype;
dr["rost"] = Convert.ToInt32(splits[3]);
dr["threshold"] = Convert.ToInt32(splits[4]);
dr["tcr"] = Convert.ToSingle(splits[5]);
dr["longitude"] = Convert.ToSingle(splits[6]);
dr["latitude"] = Convert.ToSingle(splits[7]);
dr["dop"] = Convert.ToSingle(splits[8]);
dr["fe"] = Convert.ToInt32(splits[9]);
dt.Rows.Add(dr);
}
catch
{
continue;
}
}
sr.Close();
if(dt!=null)
AddDataByLocal(dt); //批量插入
Console.WriteLine(directoy[di].ToString());
}
}
public static bool AddDataByLocal(DataTable dt)
{
bool result = false;
string constring = @"server=.\sqlexpress;integrated security=true;database=status201303";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(constring))
{
conn.Open();
try
{
using (System.Data.SqlClient.SqlBulkCopy sbc = new System.Data.SqlClient.SqlBulkCopy(constring))
{
try
{
sbc.DestinationTableName = "Late"; //服务器上目标表的名称
sbc.BatchSize = 1000;//很重要,否则会报时间超时的错误
sbc.BulkCopyTimeout = 1000;//设置允许超时时间为100秒
sbc.ColumnMappings.Add("time", "time"); //本地表和目标表列名
sbc.ColumnMappings.Add("name", "name");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("type", "type");
sbc.ColumnMappings.Add("rost", "rost"); //本地表和目标表列名
sbc.ColumnMappings.Add("threshold", "threshold");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("tcr", "tcr"); //本地表和目标表列名
sbc.ColumnMappings.Add("longitude", "longitude"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("latitude", "latitude"); //本地表和目标表列名
sbc.ColumnMappings.Add("dop", "dop"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("fe", "fe"); //如果表有多个字段,下面继续添加
sbc.WriteToServer(dt);//插入数据
result = true;
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
return result;
}
public static char getstationtype(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return 'B';
else
return 'A';
}
public static string getstationname(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return s.TrimEnd('B');
else
return s;
}
}
}
#7
哥们,你的优化在写数据库这里。我的问题在文件读取太大
#8
“卡死”很正常,如果你在界面线程执行阻塞的操作,这个期间无法响应用户操作,当然是卡死。
如果你等个几个小时乃至几天,等操作完成就恢复了。事实上,你执行插入一条数据也会“卡死”,只是也许只“卡死”0.0001秒,你感觉不出来而已。
如果你等个几个小时乃至几天,等操作完成就恢复了。事实上,你执行插入一条数据也会“卡死”,只是也许只“卡死”0.0001秒,你感觉不出来而已。
#9
多线程 也没法解决吧 总不能多个线程去操作这个文件吧 服务器内存一共就512M的话 操作1G文件我觉得怎么都是不可能的!
#10
你这里的卡死和你服务器内存大小没关系,8g内存照样卡死。
#11
使用线程试试,放到后台执行
#12
在循环开始或者结束地方加上 Application.Doevent(); 用来响应界面操作,你那个卡上是假死状态,程序一直在执行这个方法,没有时间来处理界面操作
#13
读取一个1G的文件到数据库
一次性读取是脑子进水。
一次性读取是脑子进水。
#14
设置个缓存? 怎么个搞法
#15
application.doevents()
#1
一次性都读进去 应该会很慢 ,可以试试每次读100M 。
个人理解。
个人理解。
#2
使用多线程或者并行编程,让读取操作放在后台进行,你不要一次性读取所有数据到内存中,应该设置个缓存
#3
请问,有这方面的例子么
#4
这么大的文件读取加载本身就是个问题,建议试试多线程
#5
多线程也需要内存的吧。 我们服务器内存太少了
#6
这个例子希望对你有所帮助。这个程序处理的大批量txt数据,进行处理后批量导入到数据库中,时间方面还是不错的,没有卡死等现象出现。关键是BatchSize方法的设置,一定小心,否则就出现你的情况。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace bulkdata
{
class Program
{
static void Main(string[] args)
{
string[] directoy = Directory.GetFiles(@"E:\工作\巡检分析\txt数据\3月\下");//存放了状态数据文件夹下的所有文件夹
for (int di = 0; di < directoy.Length; di++)
{
StreamReader sr = new StreamReader(directoy[di],System.Text.Encoding.Default);//最为常用的打开txt,设定编码方式
DataTable dt = new DataTable();//创建表
//添加表头
DataColumn a = new DataColumn("time", Type.GetType("System.DateTime"));
DataColumn b = new DataColumn("name", Type.GetType("System.String"));
DataColumn j = new DataColumn("type", Type.GetType("System.Char"));
DataColumn c = new DataColumn("rost", Type.GetType("System.Int32"));
DataColumn d = new DataColumn("threshold", Type.GetType("System.Int32"));
DataColumn e = new DataColumn("tcr", Type.GetType("System.Single"));
DataColumn f = new DataColumn("longitude", Type.GetType("System.Single"));
DataColumn g = new DataColumn("latitude", Type.GetType("System.Single"));
DataColumn h = new DataColumn("dop", Type.GetType("System.Single"));
DataColumn i = new DataColumn("fe", Type.GetType("System.Int32"));
dt.Columns.Add(a); dt.Columns.Add(b); dt.Columns.Add(c); dt.Columns.Add(d); dt.Columns.Add(e);
dt.Columns.Add(f); dt.Columns.Add(g); dt.Columns.Add(h); dt.Columns.Add(i); dt.Columns.Add(j);
String line;
while ((line = sr.ReadLine()) != null)
{
try
{
string[] splits = line.Split(new Char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries);//用' ', ' '分开
splits[0] = splits[0] + " " + splits[1];
char stype = getstationtype(splits[2]);
string sname = getstationname(splits[2]);
DateTime stime = DateTime.Parse(splits[0]);
if ((stime > DateTime.Parse("9999-12-31 11:59:59")) || (stime < DateTime.Parse("1753-1-1 12:00:00")))
{
continue;
}
DataRow dr = dt.NewRow();//添加行数据
dr["time"] = DateTime.Parse(splits[0]);
dr["name"] = sname;
dr["type"] = stype;
dr["rost"] = Convert.ToInt32(splits[3]);
dr["threshold"] = Convert.ToInt32(splits[4]);
dr["tcr"] = Convert.ToSingle(splits[5]);
dr["longitude"] = Convert.ToSingle(splits[6]);
dr["latitude"] = Convert.ToSingle(splits[7]);
dr["dop"] = Convert.ToSingle(splits[8]);
dr["fe"] = Convert.ToInt32(splits[9]);
dt.Rows.Add(dr);
}
catch
{
continue;
}
}
sr.Close();
if(dt!=null)
AddDataByLocal(dt); //批量插入
Console.WriteLine(directoy[di].ToString());
}
}
public static bool AddDataByLocal(DataTable dt)
{
bool result = false;
string constring = @"server=.\sqlexpress;integrated security=true;database=status201303";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(constring))
{
conn.Open();
try
{
using (System.Data.SqlClient.SqlBulkCopy sbc = new System.Data.SqlClient.SqlBulkCopy(constring))
{
try
{
sbc.DestinationTableName = "Late"; //服务器上目标表的名称
sbc.BatchSize = 1000;//很重要,否则会报时间超时的错误
sbc.BulkCopyTimeout = 1000;//设置允许超时时间为100秒
sbc.ColumnMappings.Add("time", "time"); //本地表和目标表列名
sbc.ColumnMappings.Add("name", "name");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("type", "type");
sbc.ColumnMappings.Add("rost", "rost"); //本地表和目标表列名
sbc.ColumnMappings.Add("threshold", "threshold");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("tcr", "tcr"); //本地表和目标表列名
sbc.ColumnMappings.Add("longitude", "longitude"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("latitude", "latitude"); //本地表和目标表列名
sbc.ColumnMappings.Add("dop", "dop"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("fe", "fe"); //如果表有多个字段,下面继续添加
sbc.WriteToServer(dt);//插入数据
result = true;
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
return result;
}
public static char getstationtype(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return 'B';
else
return 'A';
}
public static string getstationname(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return s.TrimEnd('B');
else
return s;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.IO;
namespace bulkdata
{
class Program
{
static void Main(string[] args)
{
string[] directoy = Directory.GetFiles(@"E:\工作\巡检分析\txt数据\3月\下");//存放了状态数据文件夹下的所有文件夹
for (int di = 0; di < directoy.Length; di++)
{
StreamReader sr = new StreamReader(directoy[di],System.Text.Encoding.Default);//最为常用的打开txt,设定编码方式
DataTable dt = new DataTable();//创建表
//添加表头
DataColumn a = new DataColumn("time", Type.GetType("System.DateTime"));
DataColumn b = new DataColumn("name", Type.GetType("System.String"));
DataColumn j = new DataColumn("type", Type.GetType("System.Char"));
DataColumn c = new DataColumn("rost", Type.GetType("System.Int32"));
DataColumn d = new DataColumn("threshold", Type.GetType("System.Int32"));
DataColumn e = new DataColumn("tcr", Type.GetType("System.Single"));
DataColumn f = new DataColumn("longitude", Type.GetType("System.Single"));
DataColumn g = new DataColumn("latitude", Type.GetType("System.Single"));
DataColumn h = new DataColumn("dop", Type.GetType("System.Single"));
DataColumn i = new DataColumn("fe", Type.GetType("System.Int32"));
dt.Columns.Add(a); dt.Columns.Add(b); dt.Columns.Add(c); dt.Columns.Add(d); dt.Columns.Add(e);
dt.Columns.Add(f); dt.Columns.Add(g); dt.Columns.Add(h); dt.Columns.Add(i); dt.Columns.Add(j);
String line;
while ((line = sr.ReadLine()) != null)
{
try
{
string[] splits = line.Split(new Char[] { ' ', ' ' }, StringSplitOptions.RemoveEmptyEntries);//用' ', ' '分开
splits[0] = splits[0] + " " + splits[1];
char stype = getstationtype(splits[2]);
string sname = getstationname(splits[2]);
DateTime stime = DateTime.Parse(splits[0]);
if ((stime > DateTime.Parse("9999-12-31 11:59:59")) || (stime < DateTime.Parse("1753-1-1 12:00:00")))
{
continue;
}
DataRow dr = dt.NewRow();//添加行数据
dr["time"] = DateTime.Parse(splits[0]);
dr["name"] = sname;
dr["type"] = stype;
dr["rost"] = Convert.ToInt32(splits[3]);
dr["threshold"] = Convert.ToInt32(splits[4]);
dr["tcr"] = Convert.ToSingle(splits[5]);
dr["longitude"] = Convert.ToSingle(splits[6]);
dr["latitude"] = Convert.ToSingle(splits[7]);
dr["dop"] = Convert.ToSingle(splits[8]);
dr["fe"] = Convert.ToInt32(splits[9]);
dt.Rows.Add(dr);
}
catch
{
continue;
}
}
sr.Close();
if(dt!=null)
AddDataByLocal(dt); //批量插入
Console.WriteLine(directoy[di].ToString());
}
}
public static bool AddDataByLocal(DataTable dt)
{
bool result = false;
string constring = @"server=.\sqlexpress;integrated security=true;database=status201303";
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(constring))
{
conn.Open();
try
{
using (System.Data.SqlClient.SqlBulkCopy sbc = new System.Data.SqlClient.SqlBulkCopy(constring))
{
try
{
sbc.DestinationTableName = "Late"; //服务器上目标表的名称
sbc.BatchSize = 1000;//很重要,否则会报时间超时的错误
sbc.BulkCopyTimeout = 1000;//设置允许超时时间为100秒
sbc.ColumnMappings.Add("time", "time"); //本地表和目标表列名
sbc.ColumnMappings.Add("name", "name");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("type", "type");
sbc.ColumnMappings.Add("rost", "rost"); //本地表和目标表列名
sbc.ColumnMappings.Add("threshold", "threshold");//如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("tcr", "tcr"); //本地表和目标表列名
sbc.ColumnMappings.Add("longitude", "longitude"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("latitude", "latitude"); //本地表和目标表列名
sbc.ColumnMappings.Add("dop", "dop"); //如果表有多个字段,下面继续添加
sbc.ColumnMappings.Add("fe", "fe"); //如果表有多个字段,下面继续添加
sbc.WriteToServer(dt);//插入数据
result = true;
}
catch (Exception ex)
{
throw ex;
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
return result;
}
public static char getstationtype(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return 'B';
else
return 'A';
}
public static string getstationname(string s)
{
char a = s[s.Length - 1];
if (a == 'B')
return s.TrimEnd('B');
else
return s;
}
}
}
#7
哥们,你的优化在写数据库这里。我的问题在文件读取太大
#8
“卡死”很正常,如果你在界面线程执行阻塞的操作,这个期间无法响应用户操作,当然是卡死。
如果你等个几个小时乃至几天,等操作完成就恢复了。事实上,你执行插入一条数据也会“卡死”,只是也许只“卡死”0.0001秒,你感觉不出来而已。
如果你等个几个小时乃至几天,等操作完成就恢复了。事实上,你执行插入一条数据也会“卡死”,只是也许只“卡死”0.0001秒,你感觉不出来而已。
#9
多线程 也没法解决吧 总不能多个线程去操作这个文件吧 服务器内存一共就512M的话 操作1G文件我觉得怎么都是不可能的!
#10
你这里的卡死和你服务器内存大小没关系,8g内存照样卡死。
#11
使用线程试试,放到后台执行
#12
在循环开始或者结束地方加上 Application.Doevent(); 用来响应界面操作,你那个卡上是假死状态,程序一直在执行这个方法,没有时间来处理界面操作
#13
读取一个1G的文件到数据库
一次性读取是脑子进水。
一次性读取是脑子进水。
#14
设置个缓存? 怎么个搞法
#15
application.doevents()