概述: 文本文件是一种非常常用的文件格式,因其通用的阅读方式而经常被用做不同单位的数据交换文件格式。 文本文件需要能够正确导入数据库, 必须要满足以下两个条件其中之一: 1:文本文件的结构格式固定,长度固定. 2:文本文件每行长度不固定,但每个字段之间有特殊符号分开. 本文给出的是满足条件1的文本文件导入到数据库的解决方法,对于满足条件2的文本文件,道理类似, 有兴趣的朋友可以自行测试,如有问题,欢迎交流和沟通!
一:问题描述:
这是老婆大人单位的一个项目,需求其实还是比较清晰的:要求编写Asp.Net程序,自动读取每天生成的文本文件, 根据业务逻辑处理后,保存到SQLSERVER数据库。 文本格式定义: 1:每一行具有相同固定格式,一行就对应于数据库中的一条记录,记录的每个字段都有明确的长度定义。 2:每一行文本都是连续的,中间没有任何的特殊的符号来区分不同的字段。 3:文本中有英文字母和数字,也可能有中文汉字。 4:格式规定,一个英文字母或数字对应的长度为1,中文汉字对应的长度为2. 根据项目需求分析,整个需求并不复杂,一般来说,文本文件需要能够正确导入数据库, 必须要满足以下两个条件其中之一: 1:文本文件的结构格式固定,长度固定. 2:文本文件每行长度不固定,但每个字段之间有特殊符号分开.
上述需求满足条件1,肯定可以能正确导入到数据库。
二:初步的解决思路和步骤 1:读取文本文件内容到数据流StreamReader 2:开始事务 3:循环从数据流中读取每一行到字符串,按表结构定义通过SubString函数对字符串进行截取到每一个字段变量。 4:定义SQL存储过程,传入步骤3中的每个字段值,在存储过程中完成每条记录的插入! 5:执行事务 6:事务回滚 7:错误消息捕捉,返回友好信息提示 8:释放相关资源
三:实际开发中出现的问题与解决方法 问题: 实际的程序中,按照文本文件定义的字段长度进行字符串截取,取出来的字符串长度与实际长度不一致,不论是使用bg2312编码还是默认编码。 具体现象通过调试跟踪,在C#中,不论是英文字母还是汉字,取出来的长度也是1,而不是如文本文件中规定的那样,汉字长度为2.导致整个字符串与实际定义的长度不一致,所以在用SubString()函数截取字符串时,无法根据数据结构定义中的长度正确取得每个字段值。 原因分析: 问题原因很明显是编码格式出现问题,汉字保存在磁盘中的编码有多种,常见的有:GB、BIG5 、Unicode、UTF-7、UTF-8等。在文本文件读取过程中, 文件的编码(Encoding)和StreamReader/Writer指定的Encoding不对应,就会出现乱码问题。虽然StreamReader可以根据文本文件格式自动识别编码格 式,正确读取不同编码格式的文本文件。但对于字符串来说,是无法识别字符串中的中文字符与英文,数字的区别,统一都作用长度为1处理。正确的处 理方法是使用将字符串转换为字节数组,对字节数组按文本文件定义的字段长度读取每个字段值。
四:修正的解决思路
1:读取文本文件内容到数据流StreamReader 2:开始事务 3:循环从数据流中读取每一行到字符串,并转换为字节数组。按表结构定义对字节数组进行截取到每一个字段变量。 4:定义SQL存储过程,传入步骤3中的每个字段值,在存储过程中完成每条记录的插入! 5:执行事务 6:事务回滚 7:错误消息捕捉,返回友好信息提示 8:释放相关资源
五:相关的文本文件处理函数参考,完整的源码见附件
1 /// <summary> 2 /// 通用函数,读文本文件 3 /// </summary> 4 /// <param name="fileName">读入的文本文件名称</param> 5 public static void ReadTextFromFileName(string fileName) 6 { 7 string strRecord = ""; 8 9 //读入文本文件时,一定要指定文件的编码格式.其中:default为文本文件本来的编码格式 10 //如果是简体中文的文本文件,也可以这样设置编码格式: System.Text.Encoding.GetEncode("gb2312") 11 //Encoding.GetEncode("gb2312")为简体中文编码格式,Encoding.GetEncode("big5")为繁体中文编码格式. 12 StreamReader reader = new StreamReader(fileName,System.Text.Encoding.Default); 13 14 da = new DataAccess(); 15 da.OpenConnection(); 16 17 //指定本次数据操作进行事务处理 18 da.StartTrans = true; 19 20 //开始事务处理 21 da.BeginTrans(); 22 23 //i is the really row 24 //j is the row of writed to database 25 int i ,j; 26 i=0; 27 j=0; 28 try 29 { 30 while (reader.Peek() >= 0) 31 { 32 strRecord = reader.ReadLine(); 33 if (StringConvertByteArray(strRecord)) 34 { 35 j++; 36 } 37 i++; 38 } 39 40 //执行事务 41 da.Commit(); 42 43 TotalLine = i; 44 RealLine = j; 45 } 46 catch (Exception ex) 47 { 48 //事务回滚 49 da.Rollback(); 50 51 52 SystemError.SystemLog("文件:" + fileName +"导入失败,错误行是第"+ i.ToString()+ "行,原因是: " + ex.Message); 53 throw new Exception(ex.Message); 54 } 55 56 //相关资源的消除 57 finally 58 { 59 reader.Close(); 60 da.CloseConnection(); 61 } 62 } 63 64 65 /// <summary> 66 /// 处理定长文本文件的函数,将字符串转换成byte[]数组 67 /// </summary> 68 /// <param name="aRecord"></param> 69 private static bool StringConvertByteArray(string aRecord) 70 { 71 //解决文本文件一行中可能存在中文的情况,将string类型转换为byte[]来达到 72 //正确处理文本文件的目的 73 byte[] repRecord = System.Text.Encoding.Default.GetBytes(aRecord); 74 75 //判断取得的文本文件长度是否等于定义的文本文件长度 76 if (repRecord.Length != iLineLength) 77 { 78 SystemError.SystemLog("文件:" + fileName +"导入出错,出错原因是文件长度不符合"); 79 throw new Exception("文件文本长度不对,导入失败,请检查文件文件格式"); 80 } 81 82 bool isInsert=false; 83 isInsert = AddRecord( 84 GetString(repRecord,0,8), 85 GetString(repRecord,8,8), 86 GetString(repRecord,16,6), 87 GetString(repRecord,22,6), 88 GetString(repRecord,28,8), 89 GetString(repRecord,36,6), 90 GetString(repRecord,42,10), 91 GetString(repRecord,52,4), 92 GetString(repRecord,56,6), 93 GetString(repRecord,62,8), 94 GetString(repRecord,70,7), 95 GetString(repRecord,77,32), 96 GetString(repRecord,109,72), 97 GetString(repRecord,181,8), 98 GetString(repRecord,189,30), 99 GetString(repRecord,219,45), 100 GetString(repRecord,264,10), 101 GetString(repRecord,274,25), 102 GetString(repRecord,299,2), 103 GetString(repRecord,301,25), 104 GetString(repRecord,326,3), 105 GetString(repRecord,329,15), 106 GetString(repRecord,344,1), 107 GetString(repRecord,345,8), 108 GetString(repRecord,353,6), 109 GetString(repRecord,359,8), 110 GetString(repRecord,367,1), 111 GetString(repRecord,368,1), 112 GetString(repRecord,369,32), 113 GetString(repRecord,401,7), 114 GetString(repRecord,408,60), 115 GetString(repRecord,468,20), 116 GetString(repRecord,488,20), 117 GetString(repRecord,508,20), 118 GetString(repRecord,528,36), 119 GetString(repRecord,564,15), 120 GetString(repRecord,579,15), 121 GetString(repRecord,594,15) 122 ); 123 return isInsert; 124 125 } 126 127 128 //private static void 129 /// <summary> 130 /// 处理长度固定的文本文,读取到每个字段的值 131 /// </summary> 132 /// <param name="aStr">文本文件的每行文本转换的Byte数组</param> 133 /// <param name="iStart">读取的起始位置</param> 134 /// <param name="iLength">读取的长度</param> 135 /// <returns>返回的字符串,对应于具体的字段值</returns> 136 private static string GetString(byte[] aStr,int iStart,int iLength) 137 { 138 139 byte[] tempStr = new byte[iLength]; 140 for ( int i = 0; i < iLength; i ++) 141 { 142 tempStr[i] = (byte)aStr.GetValue(iStart + i); 143 } 144 145 return System.Text.Encoding.Default.GetString(tempStr); 146 }
|
请发表评论