C#中读取文本文件导入SQL数据库解决方法

概述: 
   文本文件是一种非常常用的文件格式,因其通用的阅读方式而经常被用做不同单位的数据交换文件格式。 
   文本文件需要能够正确导入数据库, 
        必须要满足以下两个条件其中之一: 
            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:释放相关资源
 
 
五:相关的文本文件处理函数参考, 完整的源码见附件
 
 
     /// <summary> 
     /// 通用函数,读文本文件 
     /// </summary> 
     /// <param name="fileName">读入的文本文件名称</param> 
     public  static  void ReadTextFromFileName( string fileName)     
    { 
       string strRecord = ""; 
 
       //读入文本文件时,一定要指定文件的编码格式.其中:default为文本文件本来的编码格式 
       //如果是简体中文的文本文件,也可以这样设置编码格式: System.Text.Encoding.GetEncode("gb2312") 
       //Encoding.GetEncode("gb2312")为简体中文编码格式,Encoding.GetEncode("big5")为繁体中文编码格式. 
      StreamReader reader =  new StreamReader(fileName,System.Text.Encoding.Default); 
                         
      da =  new DataAccess(); 
      da.OpenConnection(); 
 
       //指定本次数据操作进行事务处理 
      da.StartTrans =  true
 
       //开始事务处理 
      da.BeginTrans(); 
 
       //i is the really row 
       //j is the row of writed to database 
       int i ,j; 
      i=0; 
      j=0; 
       try 
      {         
         while (reader.Peek() >= 0) 
        {            
          strRecord = reader.ReadLine(); 
           if (StringConvertByteArray(strRecord)) 
          { 
            j++; 
          } 
          i++; 
        }    
        
         //执行事务 
        da.Commit(); 
 
        TotalLine = i; 
        RealLine = j; 
      } 
       catch (Exception ex) 
      { 
         //事务回滚 
        da.Rollback(); 
 
 
        SystemError.SystemLog( "文件:" + fileName + "导入失败,错误行是第"+ i.ToString()+  "行,原因是: " + ex.Message); 
         throw  new Exception(ex.Message); 
      } 
 
             //相关资源的消除 
       finally 
      {                
        reader.Close(); 
        da.CloseConnection();         
      } 
    } 
 
 
     /// <summary> 
     /// 处理定长文本文件的函数,将字符串转换成byte[]数组 
     /// </summary> 
     /// <param name="aRecord"></param> 
     private  static  bool StringConvertByteArray( string aRecord) 
    { 
       //解决文本文件一行中可能存在中文的情况,将string类型转换为byte[]来达到 
       //正确处理文本文件的目的 
       byte[] repRecord = System.Text.Encoding.Default.GetBytes(aRecord); 
        
       //判断取得的文本文件长度是否等于定义的文本文件长度 
       if (repRecord.Length    != iLineLength) 
      { 
        SystemError.SystemLog( "文件:" + fileName + "导入出错,出错原因是文件长度不符合"); 
         throw  new Exception( "文件文本长度不对,导入失败,请检查文件文件格式"); 
      } 
 
       bool isInsert= false
      isInsert = AddRecord( 
        GetString(repRecord,0,8),    
        GetString(repRecord,8,8), 
        GetString(repRecord,16,6), 
        GetString(repRecord,22,6), 
        GetString(repRecord,28,8), 
        GetString(repRecord,36,6), 
        GetString(repRecord,42,10), 
        GetString(repRecord,52,4), 
        GetString(repRecord,56,6), 
        GetString(repRecord,62,8), 
        GetString(repRecord,70,7), 
        GetString(repRecord,77,32), 
        GetString(repRecord,109,72), 
        GetString(repRecord,181,8), 
        GetString(repRecord,189,30), 
        GetString(repRecord,219,45), 
        GetString(repRecord,264,10), 
        GetString(repRecord,274,25), 
        GetString(repRecord,299,2), 
        GetString(repRecord,301,25), 
        GetString(repRecord,326,3), 
        GetString(repRecord,329,15), 
        GetString(repRecord,344,1), 
        GetString(repRecord,345,8), 
        GetString(repRecord,353,6), 
        GetString(repRecord,359,8), 
        GetString(repRecord,367,1), 
        GetString(repRecord,368,1), 
        GetString(repRecord,369,32), 
        GetString(repRecord,401,7), 
        GetString(repRecord,408,60), 
        GetString(repRecord,468,20), 
        GetString(repRecord,488,20),         
        GetString(repRecord,508,20), 
        GetString(repRecord,528,36), 
        GetString(repRecord,564,15), 
        GetString(repRecord,579,15), 
        GetString(repRecord,594,15) 
        ); 
       return isInsert; 
                             
    } 
     
                 
     //private static void    
                 /// <summary> 
                 /// 处理长度固定的文本文,读取到每个字段的值 
                 /// </summary> 
                 /// <param name="aStr">文本文件的每行文本转换的Byte数组</param> 
                 /// <param name="iStart">读取的起始位置</param> 
                 /// <param name="iLength">读取的长度</param> 
                 /// <returns>返回的字符串,对应于具体的字段值</returns> 
     private  static  string GetString( byte[] aStr, int iStart, int iLength) 
    { 
 
       byte[] tempStr =  new  byte[iLength]; 
       for (  int i = 0; i < iLength; i ++) 
      { 
        tempStr[i] = ( byte)aStr.GetValue(iStart + i);         
      } 
 
       return System.Text.Encoding.Default.GetString(tempStr); 
    } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值