代码
/// <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);
    }
     


概述:
   文本文件是一种非常常用的文件格式,因其通用的阅读方式而经常被用做不同单位的数据交换文件格式。
   文本文件需要能够正确导入数据库,
        必须要满足以下两个条件其中之一:
            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);
    }
     


描述了如何处理具有固定格式文本文件的处理方式,并提供了操作文本文件的源代码供参考。有朋友通过留言希望提供数据操作类,本想重新整理后再放上来,但最 近事情太多,精力有限,直接把源码放上来,有兴趣的朋友请参考!

 

代码
/*
*                                                                说明
* 功能说明:数据访问封装。所有数据都要通过这个类定义的dbConnection访问数据库。同时,定义了通用的cmd,以及cmd常用的访问存储过程的方法RunPro
*    
*    
* 作者: RogerWang
*    
* 创建日期:2006-02-15
*    
*/

using System;
using System.Data;
using System.Data.SqlClient;


namespace insurer
{
  
/// <summary>
  
/// DataAccess 的摘要说明。
  
/// </summary>
  public class DataAccess
  {
    
private readonly string SQLCONNECTSTR = "server=(local);uid=sa;pwd=lwrong;database=insurer";
    
private SqlConnection dbConnection;
    
private readonly string RETUENVALUE = "RETURNVALUE";    


    
//判断要不要启动事务
                private bool startrans = false;

    
//为解决多笔数据导入的问题,特添加的事务处理属性
    private SqlTransaction trans = null;

                
    
//定义是否启动事务属性
    public bool StartTrans
    {
      
get
      {
        
return startrans;
      }
      
set
      {
        startrans 
= value;
      }
    }


    
//定义事务
    public SqlTransaction Trans
    {
      
get
      {
        
return trans;
      }
      
set
      {
        
if (value != null)
        {
          trans 
= value;
        }
      }
    }

    
//创建打开dbConnection对象
    public void OpenConnection()
    {
      
if ( dbConnection == null )
      {
        dbConnection 
= new SqlConnection(SQLCONNECTSTR);
      }

      
if ( dbConnection.State == ConnectionState.Closed )
      {
        
try
        {
          dbConnection.Open();
        }
        
catch(Exception ex)
        {
          SystemError.SystemLog(ex.Message);
        }
        
finally
        {
        }
      }
    }

    
//释放dbConnection对象
    public void CloseConnection()
    {
      
if (dbConnection != null)
      {
        
if (dbConnection.State == ConnectionState.Open)
        {
          dbConnection.Dispose();
          dbConnection 
= null;
        }
      }
    }


    
//

    
//创建cmd,注意dbconnection在该函数中创建,但没有在这函数中释放。
    
//在正确的面向对象设计方法中,对象应该是谁创建,谁就应该负责释放。按这个观点,这个过程有些不安全!!!!
        private SqlCommand CreateCommand(string ProName,SqlParameter[] prams)
    {
      OpenConnection();
      SqlCommand cmd 
= new SqlCommand(ProName,dbConnection);
      cmd.CommandType 
= CommandType.StoredProcedure;


      
//如果进行事务处理,那么对cmd的Transaction的事务赋值
      if (StartTrans)
      {
        cmd.Transaction 
= Trans;
      }


      
if ( prams != null)
      {
        
foreach(SqlParameter parameter in prams)
        {
          cmd.Parameters.Add(parameter);
        }
      }

      
//cmd.Parameters.Add(

      
return cmd;

    }


    
/// <summary>
    
/// 创建cmd,并执行相应的操作。 然后释放cmd!
    
///    
    
/// 该函数是执行cmd没有返回值,且没有参数的方法。
    
/// </summary>
    
/// <param name="ProName"></param>
    public bool RunProc(string ProName)
    {
      SqlCommand cmd 
= CreateCommand(ProName,null);

      
bool k = false;
      
try
      {
        k 
= (bool)cmd.ExecuteScalar();
      }
      
catch(Exception ex)
      {
        SystemError.SystemLog(ex.Message);
      }
      
finally
      {
        cmd.Dispose();
      }
      
return k;

    }

    
/// <summary>
    
/// 创建cmd,并执行相应的操作。 然后释放cmd!
    
///    
    
/// 该函数是执行cmd没有返回值,但有参数的方法。
    
/// </summary>
    
/// <param name="ProName"></param>
    
/// <param name="prams"></param>
    public bool RunProc(string ProName,SqlParameter[] prams)
    {
      SqlCommand cmd 
= CreateCommand(ProName,prams);

      
bool k = false;
      
try
      {
        k 
= (bool) cmd.ExecuteScalar();
      }
      
catch(Exception ex)
      {
        SystemError.SystemLog(ex.Message);
      }
      
finally
      {    
        cmd.Dispose();
        
//Close();
      }
      
return k;
    }

    
/// <summary>
    
/// 创建cmd,并执行相应的操作。 然后释放cmd!
    
///    
    
/// 该函数是执行cmd带有返回值,但没有参数的方法。    
    
/// </summary>
    
/// <param name="ProName"></param>
    
/// <param name="dataReader"></param>
    public void RunProc(string ProName,out SqlDataReader dataReader)
    {
      SqlCommand cmd 
= CreateCommand(ProName,null);
      dataReader 
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
      
try
      {
        
      }
      
catch(Exception ex)
      {
        SystemError.SystemLog(ex.Message);
      }
      
finally
      {
        cmd.Dispose();
      }
    }

    
/// <summary>
                
/// 创建cmd,并执行相应的操作。 然后释放cmd!
    
///    
    
/// 该函数是执行cmd带有返回值,且有参数的方法。
    
/// </summary>
    
/// <param name="ProName"></param>
    
/// <param name="prams"></param>
    
/// <param name="dataReader"></param>
    public void RunProc(string ProName,SqlParameter[] prams,out SqlDataReader dataReader)
    {
      SqlCommand cmd 
= CreateCommand(ProName,prams);
      dataReader 
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
      
try
      {
        
      }
      
catch(Exception ex)
      {
        SystemError.SystemLog(ex.Message);
      }
      
finally
      {
        cmd.Dispose();
      }
    }


    
/// <summary>
    
/// 创建cmd的参数
    
/// 该方法的思路就是按条件生成一个SqlParameter对象。
    
/// 生成对象后,再给对象赋相应的返回值类型
    
/// </summary>
    
/// <param name="ParamName"></param>
    
/// <param name="DbType"></param>
    
/// <param name="size"></param>
    
/// <param name="direction"></param>
    
/// <param name="Value"></param>
    
/// <returns></returns>
    public SqlParameter CreateParam(string ParamName, SqlDbType DbType, int size,ParameterDirection direction,object Value)
    {
      SqlParameter param;

      
if (size > 0)
      {
        param 
= new SqlParameter(ParamName,DbType,size);
      }
      
else
      {
        param 
= new SqlParameter(ParamName,DbType);
      }

      param.Direction 
= direction;

      param.Value 
= Value;

      
return param;
    }

    
/// <summary>
    
/// 创建cmd的输入参数
    
/// </summary>
    
/// <param name="ParamName"></param>
    
/// <param name="DbType"></param>
    
/// <param name="size"></param>
    
/// <param name="Value"></param>
    
/// <returns></returns>
    public SqlParameter CreateInParam(string ParamName, SqlDbType DbType, int size, object Value)
    {
      
return CreateParam(ParamName,DbType,size,ParameterDirection.Input,Value);
    }

    
/// <summary>
    
/// 创建cmd的输出参数
    
/// </summary>
    
/// <param name="ParamName"></param>
    
/// <param name="DbType"></param>
    
/// <param name="size"></param>
    
/// <returns></returns>
    public SqlParameter CreateOutParam(string ParamName, SqlDbType DbType, int size)
    {
      
return CreateParam(ParamName,DbType,size,ParameterDirection.Output,null);
    }

    
/// <summary>
    
/// 创建cmd带有返回值的参数
    
/// </summary>
    
/// <param name="ParamName"></param>
    
/// <param name="DbType"></param>
    
/// <param name="size"></param>
    
/// <returns></returns>
    public SqlParameter CreateReturnParam(string ParamName,SqlDbType DbType, int size)
    {
      
return CreateParam(ParamName,DbType,size,ParameterDirection.ReturnValue,null);
    }


    
//开始一个事务
    public void BeginTrans()
    {
      OpenConnection();

      Trans 
= dbConnection.BeginTransaction(IsolationLevel.Serializable);
    }


    
public void Commit()
    {
      
if (Trans != null)
      {
        Trans.Commit();
      }
    }

    
public void Rollback()
    {
      
if (Trans != null)
      {
        Trans.Rollback();
      }
    }
  }


 

 

 

 

 

posted on 2010-01-12 16:44  superlee  阅读(1203)  评论(0编辑  收藏  举报