从DataSet导出Txt
网上已经存在很多从DataSet导出到Word、Excel、Txt等的文章了,为什么还要写这篇文章呢,因为搜索了好长时间都没有找到符合要求的(不代表没有),只好自己动手写一个。后面我还遇到了问题,希望园子里的朋友帮忙解决一下,看有没有更好的办法。
在这篇文章中,我涉及两个导出的问题。第一个问题是导出的每一列根据这一列的长度自动分配宽度,这样说还是不够明了,下面通过例子来看。
首先,构造我们的DataSet。本来想从数据库中查询得到,这样虽然麻烦点,但是更直接。
DataSet ds = new DataSet(); DataTable table = new DataTable(); DataColumn[] columns = new DataColumn[7]; columns[0] = new DataColumn("EmpNo"); columns[1] = new DataColumn("EmpName"); columns[2] = new DataColumn("Dept"); columns[3] = new DataColumn("Post"); columns[4] = new DataColumn("Salary"); columns[5] = new DataColumn("Bank"); columns[6] = new DataColumn("BankNo"); table.Columns.AddRange(columns); DataRow row1 = table.NewRow(); row1["EmpNo"] = "1001"; row1["EmpName"] = "刘德华"; row1["Dept"] = "办公室"; row1["Post"] = "总经理"; row1["Salary"] = 6000; row1["Bank"] = "建设银行"; row1["BankNo"] = "5475694879437594"; DataRow row2 = table.NewRow(); row2["EmpNo"] = "1002"; row2["EmpName"] = "周迅"; row2["Dept"] = "财务"; row2["Post"] = "出纳"; row2["Salary"] = 4000; row2["Bank"] = "建设银行"; row2["BankNo"] = "5475695489548395"; DataRow row3 = table.NewRow(); row3["EmpNo"] = "1003"; row3["EmpName"] = "abc"; row3["Dept"] = "信息部"; row3["Post"] = "程序员"; row3["Salary"] = 5000; row3["Bank"] = "建设银行"; row3["BankNo"] = "5475763489548395"; table.Rows.Add(row1); table.Rows.Add(row2); table.Rows.Add(row3); ds.Tables.Add(table);
在上面的代码中有三条数据。
第二,写导出的方法。
/// <summary> /// DataSet导出为Txt /// </summary> /// <param name="ds"></param> /// <param name="fileName">导出txt文件名</param> /// <param name="page"></param> public static void ToTxt(DataSet ds, string fileName, Page page) { StringBuilder sb = new StringBuilder(); DataTable table = ds.Tables[0]; DataRowCollection rows = table.Rows; DataColumnCollection columns = table.Columns; //行数 int rowCount = rows.Count; //列数 int columnCount = columns.Count; //每列的最大长度 int[] columnMaxLength = new int[columnCount]; //遍历所有的记录获得每列的最大长度 for (int i = 0; i < columnCount; i++) { int[] tmps = new int[rowCount]; for (int j = 0; j < rowCount; j++) { tmps[j] = System.Text.Encoding.Default.GetByteCount(rows[j][i].ToString()); } columnMaxLength[i] = ArrayMaxValue(tmps); } //将上面取的最大长度与列名比较 for (int i = 0; i < columnCount; i++) { if (columnMaxLength[i] < System.Text.Encoding.Default.GetByteCount(columns[i].ColumnName)) { columnMaxLength[i] = System.Text.Encoding.Default.GetByteCount(columns[i].ColumnName); } } //将列名附加到字符串 for (int i = 0; i < columnCount; i++) { int a = columnMaxLength[i] - System.Text.Encoding.Default.GetByteCount(columns[i].ColumnName); StringBuilder sb1 = new StringBuilder(a); //每列之间间隔3 for (int j = 0; j < a + 3; j++) { sb1.Append(" "); } sb.Append(columns[i].ColumnName).Append(sb1.ToString()); } sb.AppendLine(); sb.AppendLine(); //将记录附加到字符串 for (int i = 0; i < rowCount; i++) { for (int j = 0; j < columnCount; j++) { int a = columnMaxLength[j] - System.Text.Encoding.Default.GetByteCount(rows[i][j].ToString()); StringBuilder sb1 = new StringBuilder(a); for (int k = 0; k < a + 3; k++) { sb1.Append(" "); } sb.Append(rows[i][j]).Append(sb1.ToString()); } sb.AppendLine(); } HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Buffer = false; HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8; HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpContext.Current.Server.HtmlEncode(fileName) + ".txt"); HttpContext.Current.Response.ContentType = "text/plain"; page.EnableViewState = false; HttpContext.Current.Response.Write(sb.ToString()); HttpContext.Current.Response.End(); } /// <summary> /// 取数组的最大值 /// </summary> /// <param name="arr"></param> /// <returns></returns> private static int ArrayMaxValue(int[] arr) { int maxInt = arr[0]; for (int i = 0; i < arr.Length; i++) { if (arr[i] > maxInt) { maxInt = arr[i]; } } return maxInt; }
在上面的方法中,应该可以改正减少很多代码,如果感兴趣的朋友可以修改。方法中,我使用的是字符串的字节长度,而不是字符串的长度,如果使用字符串长度,一个英文字母和一个汉字的长度都是1,显然汉字要宽。我发现一个汉字的宽度和2个英文字母的宽度差不多(看着差不多),一个汉字又等于2个字节,所以就是用了字节长度。
最后,导出的效果如下图所示:
public static void ToTxt(DataSet ds, string fileName, Page page) { StringBuilder sb = new StringBuilder(); DataTable table = ds.Tables[0]; DataRowCollection rows = table.Rows; DataColumnCollection columns = table.Columns; int rowCount = rows.Count; int columnCount = columns.Count; int k = 1; for (int i = 0; i < rows.Count; i++) { decimal factSalary = Convert.ToDecimal(rows[i]["FactSalary"]); int a = (int)(factSalary - factSalary % 5000) / 5000; if (a > 0) { for (int j = 0; j < a; j++) { sb.Append(i + k + j).Append(","); sb.Append(rows[i]["BankNo"].ToString()).Append(","); sb.Append(rows[i]["EmpName"].ToString()).Append(","); sb.Append(5000).Append(","); sb.Append("公务报销"); sb.AppendLine(); } k += a; sb.Append(i + k).Append(","); sb.Append(rows[i]["BankNo"].ToString()).Append(","); sb.Append(rows[i]["EmpName"].ToString()).Append(","); sb.Append(factSalary % 5000).Append(","); sb.Append("公务报销"); sb.AppendLine(); } else { sb.Append(i + k).Append(","); sb.Append(rows[i]["BankNo"].ToString()).Append(","); sb.Append(rows[i]["EmpName"].ToString()).Append(","); sb.Append(rows[i]["FactSalary"]).Append(","); sb.Append("公务报销"); sb.AppendLine(); } } HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Buffer = false; HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8; HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpContext.Current.Server.HtmlEncode(fileName) + ".txt"); HttpContext.Current.Response.ContentType = "text/plain"; page.EnableViewState = false; HttpContext.Current.Response.Write(sb.ToString()); HttpContext.Current.Response.End(); }
第二个问题就是导出的每个TXT中,总的金额不能超过10万,单笔不能超过5000,如果超过5000,就要进行拆分。
我写了一个方法实现了单笔超过5000的进行拆分,但是一个TXT中总金额不超过10万,还没有写,一种解决方案就是先创建一个文件,将不超过10万的导入到这个文件中,然后再创建一个文件,继续导入到这个文件中,如此,直到导出完成。
稍微修改上面的DataSet数据,金额分别修改为6000,5001,10001最后导出的效果如下图所示:
时间不早了,希望园子里的朋友能给出更好的解决方案,谢谢了!