MultiRecordEngine.cs :  » Persistence-Frameworks » FileHelpers-Library » FileHelpers » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Persistence Frameworks » FileHelpers Library 
FileHelpers Library » FileHelpers » MultiRecordEngine.cs
#undef GENERICS
//#define GENERICS
//#if NET_2_0

#region "   Copyright 2005-07 to Marcos Meli - http://www.marcosmeli.com.ar" 

// Errors, suggestions, contributions, send a mail to: marcos@filehelpers.com.

#endregion

using System;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Text;
using FileHelpers.MasterDetail;

namespace FileHelpers{

  #region "  Delegate  "

  /// <summary>
  /// Delegate thats determines the Type of the current record (Master, Detail, Skip)
  /// </summary>
  /// <param name="recordString">The string of the current record.</param>
  /// <param name="engine">The engine that calls the selector.</param>
  /// <returns>the action used for the current record (Master, Detail, Skip)</returns>
  public delegate Type RecordTypeSelector(MultiRecordEngine engine, string recordString);

  #endregion

  /// <summary><para>This engine allows you to parse and write files that contain
    /// records of different types and that are in a linear relationship</para>
    /// <para>(for Master-Detail check the <see cref="MasterDetailEngine"/>)</para>
  /// </summary>
  /// <seealso href="quick_start.html">Quick Start Guide</seealso>
  /// <seealso href="class_diagram.html">Class Diagram</seealso>
  /// <seealso href="examples.html">Examples of Use</seealso>
  /// <seealso href="example_datalink.html">Example of the DataLink</seealso>
  /// <seealso href="attributes.html">Attributes List</seealso>
#if NET_2_0
    [DebuggerDisplay("MultiRecordEngine for types: {ListTypes()}. ErrorMode: {ErrorManager.ErrorMode.ToString()}. Encoding: {Encoding.EncodingName}")]
#endif
#if ! GENERICS
  public sealed class MultiRecordEngine : 
    EngineBase, IEnumerable, IDisposable
#else
  public sealed class MultiRecordEngine<M,D> : 
    EngineBase, IEnumerable, IDisposable
#endif
  {
#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        private RecordInfo[] mMultiRecordInfo;
#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        private Hashtable mRecordInfoHash;
#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        private RecordTypeSelector mRecordSelector;

        private string ListTypes()
        {
            string res = string.Empty;
            bool first = true;
            foreach (Type t in mRecordInfoHash.Keys)
          {
                if (first)
                    first = false;
                else
                    res += ", ";

                res += t.Name;
          }

            return res;
        }


    /// <summary>
    /// The Selector used by the engine in Read operations to determine the Type to use.
    /// </summary>
    public RecordTypeSelector RecordSelector
    {
      get { return mRecordSelector; }
      set { mRecordSelector = value; }
    }

#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        private Type[] mTypes;
    
    #region "  Constructor  "

    /// <summary>Create a new instance of the MultiRecordEngine</summary>
    /// <param name="recordTypes">The Types of the records that this engine can handle.</param>
    public MultiRecordEngine(params Type[] recordTypes) : this(null, recordTypes)
    {
    }

    /// <summary>Create a new instance of the MultiRecordEngine</summary>
    /// <param name="recordTypes">The Types of the records that this engine can handle.</param>
    /// <param name="recordSelector">Used only in read operations. The selector indicates to the engine what Type to use in each read line.</param>
    public MultiRecordEngine(RecordTypeSelector recordSelector, params Type[] recordTypes) : base(GetFirstType(recordTypes))
    {
      mTypes = recordTypes;
      mMultiRecordInfo = new RecordInfo[mTypes.Length];
      mRecordInfoHash = new Hashtable(mTypes.Length);
      for(int i=0; i < mTypes.Length; i++)
      {
        if (mTypes[i] == null)
          throw new BadUsageException("The type at index "+ i.ToString() + " is null.");

        if (mRecordInfoHash.Contains(mTypes[i]))
          throw new BadUsageException("The type '"+ mTypes[i].Name + " is already in the engine. You can't pass the same type twice to the constructor.");

        mMultiRecordInfo[i] = new RecordInfo(mTypes[i]); 
        mRecordInfoHash.Add(mTypes[i], mMultiRecordInfo[i]);
      }
      mRecordSelector = recordSelector;
    }

    #endregion

    #region "  Events  "

#if NET_1_1
    
    /// <summary>Called in read operations just before the record string is translated to a record.</summary>
    public event BeforeReadRecordHandler BeforeReadRecord;
    /// <summary>Called in read operations just after the record was created from a record string.</summary>
    public event AfterReadRecordHandler AfterReadRecord;
    /// <summary>Called in write operations just before the record is converted to a string to write it.</summary>
    public event BeforeWriteRecordHandler BeforeWriteRecord;
    /// <summary>Called in write operations just after the record was converted to a string.</summary>
    public event AfterWriteRecordHandler AfterWriteRecord;

    private bool OnBeforeReadRecord(string line)
    {
      if (BeforeReadRecord != null)
      {
        BeforeReadRecordEventArgs e = null;
        e = new BeforeReadRecordEventArgs(line, LineNumber);
        BeforeReadRecord(this, e);

        return e.SkipThisRecord;
      }

      return false;
    }

    private bool OnAfterReadRecord(string line, object record)
    {
      if (mRecordInfo.mNotifyRead)
        ((INotifyRead)record).AfterRead(this, line);

      if (AfterReadRecord != null)
      {
        AfterReadRecordEventArgs e = null;
        e = new AfterReadRecordEventArgs(line, record, LineNumber);
        AfterReadRecord(this, e);
              
        return e.SkipThisRecord;
      }
      return false;
    }

    private bool OnBeforeWriteRecord(object record)
    {
      if (mRecordInfo.mNotifyWrite)
        ((INotifyWrite)record).BeforeWrite(this);
      
      if (BeforeWriteRecord != null)
      {
        BeforeWriteRecordEventArgs e = null;
        e = new BeforeWriteRecordEventArgs(record, LineNumber);
        BeforeWriteRecord(this, e);

        return e.SkipThisRecord;
      }

      return false;
    }

    private string OnAfterWriteRecord(string line, object record)
    {
      if (AfterWriteRecord != null)
      {
        AfterWriteRecordEventArgs e = null;
        e = new AfterWriteRecordEventArgs(record, LineNumber, line);
        AfterWriteRecord(this, e);
        return e.RecordLine;
      }
      return line;
    }

#else
    /// <summary>Called in read operations just before the record string is translated to a record.</summary>
    public event EventHandler<BeforeReadRecordEventArgs<object>> BeforeReadRecord;
    /// <summary>Called in read operations just after the record was created from a record string.</summary>
    public event EventHandler<AfterReadRecordEventArgs<object>> AfterReadRecord;
    /// <summary>Called in write operations just before the record is converted to a string to write it.</summary>
    public event EventHandler<BeforeWriteRecordEventArgs<object>> BeforeWriteRecord;
    /// <summary>Called in write operations just after the record was converted to a string.</summary>
    public event EventHandler<AfterWriteRecordEventArgs<object>> AfterWriteRecord;


        private bool OnBeforeReadRecord(string line)
        {
            if (BeforeReadRecord != null)
            {
                BeforeReadRecordEventArgs<object> e = null;
                e = new BeforeReadRecordEventArgs<object>(line, LineNumber);
                BeforeReadRecord(this, e);

                return e.SkipThisRecord;
            }

            return false;
        }

        private bool OnAfterReadRecord(string line, object record)
        {
      if (mRecordInfo.mNotifyRead)
        ((INotifyRead)record).AfterRead(this, line);

            if (AfterReadRecord != null)
            {
                AfterReadRecordEventArgs<object> e = null;
                e = new AfterReadRecordEventArgs<object>(line, record, LineNumber);
                AfterReadRecord(this, e);
              
              return e.SkipThisRecord;
            }
          return false;
        }

        private bool OnBeforeWriteRecord(object record)
        {
      if (mRecordInfo.mNotifyWrite)
        ((INotifyWrite)record).BeforeWrite(this);
      
      if (BeforeWriteRecord != null)
            {
                BeforeWriteRecordEventArgs<object> e = null;
                e = new BeforeWriteRecordEventArgs<object>(record, LineNumber);
                BeforeWriteRecord(this, e);

                return e.SkipThisRecord;
            }

            return false;
        }

        private string OnAfterWriteRecord(string line, object record)
        {
            if (AfterWriteRecord != null)
            {
                AfterWriteRecordEventArgs<object> e = null;
                e = new AfterWriteRecordEventArgs<object>(record, LineNumber, line);
                AfterWriteRecord(this, e);
                return e.RecordLine;
            }
            return line;
        }

#endif

    #endregion

    #region "  ReadFile  "

    /// <summary>
    /// Read a File and returns the records.
    /// </summary>
    /// <param name="fileName">The file with the records.</param>
    /// <returns>The read records of the differents types all mixed.</returns>
    public object[] ReadFile(string fileName)
    {
      using (StreamReader fs = new StreamReader(fileName, mEncoding, true))
      {
        object[] tempRes;
        tempRes = ReadStream(fs);
        fs.Close();

        return tempRes;
      }

    }

    #endregion

    #region "  ReadStream  "

    /// <include file='MultiRecordEngine.docs.xml' path='doc/ReadStream/*'/>
    public object[] ReadStream(TextReader reader)
    {
      if (reader == null)
        throw new ArgumentNullException("reader", "The reader of the Stream cant be null");

      if (mRecordSelector == null)
        throw new BadUsageException("The Recordselector cant be null, please pass a not null Selector in the constructor.");

      ResetFields();
      mHeaderText = String.Empty;
      mFooterText = String.Empty;

      ArrayList resArray = new ArrayList();

      ForwardReader freader = new ForwardReader(reader, mMultiRecordInfo[0].mIgnoreLast);
      freader.DiscardForward = true;

      string currentLine, completeLine;

      mLineNumber = 1;

      completeLine = freader.ReadNextLine();
      currentLine = completeLine;

#if !MINI
      ProgressHelper.Notify(mNotifyHandler, mProgressMode, 0, -1);
#endif
      int currentRecord = 0;

      if (mMultiRecordInfo[0].mIgnoreFirst > 0)
      {
        for (int i = 0; i < mMultiRecordInfo[0].mIgnoreFirst && currentLine != null; i++)
        {
          mHeaderText += currentLine + StringHelper.NewLine;
          currentLine = freader.ReadNextLine();
          mLineNumber++;
        }
      }


      bool byPass = false;

      //      MasterDetails record = null;
      ArrayList tmpDetails = new ArrayList();

      LineInfo line = new LineInfo(currentLine);
      line.mReader = freader;
      
      while (currentLine != null)
      {
        try
        {

          mTotalRecords++;
          currentRecord++;
          
          line.ReLoad(currentLine);

          bool skip = false;
#if !MINI
          ProgressHelper.Notify(mNotifyHandler, mProgressMode, currentRecord, -1);
          skip = OnBeforeReadRecord(currentLine);
#endif

          Type currType = mRecordSelector(this, currentLine);

          if (currType != null)
          {
            RecordInfo info = (RecordInfo) mRecordInfoHash[currType];

            if (skip == false)
            {
              object record = info.StringToRecord(line);

#if !MINI
              skip = OnAfterReadRecord(currentLine, record);
#endif
                          
              if (skip == false && record != null)
                resArray.Add(record);

            }

          }

        }
        catch (Exception ex)
        {
          switch (mErrorManager.ErrorMode)
          {
            case ErrorMode.ThrowException:
              byPass = true;
              throw;
            case ErrorMode.IgnoreAndContinue:
              break;
            case ErrorMode.SaveAndContinue:
              ErrorInfo err = new ErrorInfo();
              err.mLineNumber = freader.LineNumber;
              err.mExceptionInfo = ex;
              //              err.mColumnNumber = mColumnNum;
              err.mRecordString = completeLine;

              mErrorManager.AddError(err);
              break;
          }
        }
        finally
        {
          if (byPass == false)
          {
            currentLine = freader.ReadNextLine();
            completeLine = currentLine;
            mLineNumber = freader.LineNumber;
          }
        }

      }

      if (mMultiRecordInfo[0].mIgnoreLast > 0)
      {
        mFooterText = freader.RemainingText;
      }

      return resArray.ToArray();
    }

    #endregion

    #region "  ReadString  "

    /// <include file='MultiRecordEngine.docs.xml' path='doc/ReadString/*'/>
    public object[] ReadString(string source)
    {
      StringReader reader = new StringReader(source);
      object[] res = ReadStream(reader);
      reader.Close();
      return res;
    }

    #endregion

    #region "  WriteFile  "

    /// <include file='MultiRecordEngine.docs.xml' path='doc/WriteFile/*'/>
    public void WriteFile(string fileName, IEnumerable records)
    {
      WriteFile(fileName, records, -1);
    }

    /// <include file='MultiRecordEngine.docs.xml' path='doc/WriteFile2/*'/>
    public void WriteFile(string fileName, IEnumerable records, int maxRecords)
    {
      using (StreamWriter fs = new StreamWriter(fileName, false, mEncoding))
      {
        WriteStream(fs, records, maxRecords);
        fs.Close();
      }

    }

    #endregion

    #region "  WriteStream  "

    /// <summary>
    /// Write the records to a file
    /// </summary>
    /// <param name="writer"></param>
    /// <param name="records"></param>
    public void WriteStream(TextWriter writer, IEnumerable records)
    {
      WriteStream(writer, records, -1);
    }

    /// <include file='MultiRecordEngine.docs.xml' path='doc/WriteStream2/*'/>
    public void WriteStream(TextWriter writer, IEnumerable records, int maxRecords)
    {
      if (writer == null)
        throw new ArgumentNullException("writer", "The writer of the Stream can be null");

      if (records == null)
        throw new ArgumentNullException("records", "The records can be null. Try with an empty array.");

      ResetFields();

      if (mHeaderText != null && mHeaderText.Length != 0)
        if (mHeaderText.EndsWith(StringHelper.NewLine))
          writer.Write(mHeaderText);
        else
          writer.WriteLine(mHeaderText);


      string currentLine = null;

      //ConstructorInfo constr = mType.GetConstructor(new Type[] {});
      int max = maxRecords;

      if (records is IList)
                max = Math.Min(max < 0 ? int.MaxValue : max, ((IList)records).Count);


#if !MINI
      ProgressHelper.Notify(mNotifyHandler, mProgressMode, 0, max);
                
#endif
      int recIndex = 0;

      foreach (object rec in records)
      {
        if (recIndex == maxRecords)
          break;
        try
        {
          if (rec == null)
            throw new BadUsageException("The record at index " + recIndex.ToString() + " is null.");

          bool skip = false;
#if !MINI
          ProgressHelper.Notify(mNotifyHandler, mProgressMode, recIndex+1, max);
          skip = OnBeforeWriteRecord(rec);
#endif

          RecordInfo info = (RecordInfo) mRecordInfoHash[rec.GetType()];

          if (info == null)
            throw new BadUsageException("The record at index " + recIndex.ToString() + " is of type '" + rec.GetType().Name+"' and the engine dont handle this type. You can add it to the constructor.");

          if (skip == false)
          {
            currentLine = info.RecordToString(rec);
#if !MINI
            currentLine = OnAfterWriteRecord(currentLine, rec);
#endif
            writer.WriteLine(currentLine);
          }

        }
        catch (Exception ex)
        {
          switch (mErrorManager.ErrorMode)
          {
            case ErrorMode.ThrowException:
              throw;
            case ErrorMode.IgnoreAndContinue:
              break;
            case ErrorMode.SaveAndContinue:
              ErrorInfo err = new ErrorInfo();
              err.mLineNumber = mLineNumber;
              err.mExceptionInfo = ex;
              //              err.mColumnNumber = mColumnNum;
              err.mRecordString = currentLine;
              mErrorManager.AddError(err);
              break;
          }
        }
        recIndex++;
      }

      mTotalRecords = recIndex;

      if (mFooterText != null && mFooterText != string.Empty)
        if (mFooterText.EndsWith(StringHelper.NewLine))
          writer.Write(mFooterText);
        else
          writer.WriteLine(mFooterText);

    }

    #endregion

    #region "  WriteString  "

    /// <include file='MultiRecordEngine.docs.xml' path='doc/WriteString/*'/>
    public string WriteString(IEnumerable records)
    {
      return WriteString(records, -1);
    }

    /// <include file='MultiRecordEngine.docs.xml' path='doc/WriteString2/*'/>
    public string WriteString(IEnumerable records, int maxRecords)
    {
      StringBuilder sb = new StringBuilder();
      StringWriter writer = new StringWriter(sb);
      WriteStream(writer, records, maxRecords);
      string res = writer.ToString();
      writer.Close();
      return res;
    }

    #endregion

    #region "  AppendToFile  "

    /// <include file='MultiRecordEngine.docs.xml' path='doc/AppendToFile1/*'/>
    public void AppendToFile(string fileName, object record)
    {
      AppendToFile(fileName, new object[] {record});
    }

    /// <include file='MultiRecordEngine.docs.xml' path='doc/AppendToFile2/*'/>
    public void AppendToFile(string fileName, IEnumerable records)
    {
      using(TextWriter writer = StreamHelper.CreateFileAppender(fileName, mEncoding, true, false))
      {
        mHeaderText = String.Empty;
        mFooterText = String.Empty;

        WriteStream(writer, records);
        writer.Close();
      }

    }

    #endregion

    private static Type GetFirstType(Type[] types)
    {
      if (types == null)
        throw new BadUsageException("A null Type[] is not valid for the MultiRecordEngine.");
      else if (types.Length == 0)
        throw new BadUsageException("An empty Type[] is not valid for the MultiRecordEngine.");
      else if (types.Length == 1)
        throw new BadUsageException("You only provide one type to the engine constructor. You need 2 or more types, for one type you can use the FileHelperEngine.");
      else
        return types[0];
    }
    

    // ASYNC METHODS --------------

#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        ForwardReader mAsyncReader;
#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        TextWriter mAsyncWriter;

    #region "  LastRecord  "

#if NET_2_0
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
#endif
        private object mLastRecord;

    /// <include file='FileHelperAsyncEngine.docs.xml' path='doc/LastRecord/*'/>
    public object LastRecord
    {
      get { return mLastRecord; }
    }

    #endregion

    #region "  BeginReadStream"


    /// <summary>
    /// Method used to use this engine in Async mode. Work together with <see cref="ReadNext"/>. (Remember to call Close after read the data)
    /// </summary>
    /// <param name="reader">The source Reader.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public void BeginReadStream(TextReader reader)
    {
      if (reader == null)
        throw new ArgumentNullException("The TextReader cant be null.");

      ResetFields();
      mHeaderText = String.Empty;
      mFooterText = String.Empty;

      if (mRecordInfo.mIgnoreFirst > 0)
      {
        for (int i = 0; i < mRecordInfo.mIgnoreFirst; i++)
        {
          string temp = reader.ReadLine();
          mLineNumber++;
          if (temp != null)
            mHeaderText += temp + StringHelper.NewLine;
          else
            break;
        }
      }

      mAsyncReader = new ForwardReader(reader, mRecordInfo.mIgnoreLast, mLineNumber);
      mAsyncReader.DiscardForward = true;
    }

    #endregion

    #region "  BeginReadFile  "

    /// <summary>
    /// Method used to use this engine in Async mode. Work together with <see cref="ReadNext"/>. (Remember to call Close after read the data)
    /// </summary>
    /// <param name="fileName">The source file.</param>
    public void BeginReadFile(string fileName)
    {
      BeginReadStream(new StreamReader(fileName, mEncoding, true));
    }

    /// <summary>
    /// Method used to use this engine in Async mode. Work together with <see cref="ReadNext"/>. (Remember to call Close after read the data)
    /// </summary>
    /// <param name="sourceData">The source String</param>
    public void BeginReadString(string sourceData)
    {
      if (sourceData == null)
        sourceData = String.Empty;

      BeginReadStream(new StringReader(sourceData));
    }

    #endregion
    

    /// <summary>
    /// Save all the buffered data for write to the disk. 
    /// Useful to long opened async engines that wants to save pending values or for engines used for logging.
    /// </summary>
    public void Flush()
    {
      if (mAsyncWriter != null)
        mAsyncWriter.Flush();
    }


    #region "  Close  "
    /// <summary>
    /// Close the underlining Readers and Writers. (if any)
    /// </summary>
    public void Close()
    {
      try
      {
        if (mAsyncReader != null)
          mAsyncReader.Close();

        mAsyncReader = null;
      }
      catch
      {}

      try
      {
        if (mAsyncWriter != null)
        {
          if (mFooterText != null && mFooterText != string.Empty)
            if (mFooterText.EndsWith(StringHelper.NewLine))
              mAsyncWriter.Write(mFooterText);
            else
              mAsyncWriter.WriteLine(mFooterText);

          mAsyncWriter.Close();
          mAsyncWriter = null;
        }

      }
      catch
      {}

    }

    #endregion
    
    
    // DIFFERENT FROM THE ASYNC ENGINE
    
    #region "  ReadNext  "

    /// <include file='FileHelperAsyncEngine.docs.xml' path='doc/ReadNext/*'/>
    public object ReadNext()
    {
      if (mAsyncReader == null)
        throw new BadUsageException("Before call ReadNext you must call BeginReadFile or BeginReadStream.");

      ReadNextRecord();

      return mLastRecord;
    }

    private void ReadNextRecord()
    {

      string currentLine = mAsyncReader.ReadNextLine();
      mLineNumber++;

      bool byPass = false;

      mLastRecord = null;

      LineInfo line = new LineInfo(currentLine);
      line.mReader = mAsyncReader;
      
    
      while (true)
      {
        if (currentLine != null)
        {
          try
          {
            mTotalRecords++;

            Type currType = mRecordSelector(this, currentLine);
            
            line.ReLoad(currentLine);

            if (currType != null)
            {
              RecordInfo info = (RecordInfo) mRecordInfoHash[currType];
              mLastRecord = info.StringToRecord(line);

              if (mLastRecord != null)
              {
                byPass = true;
                return;
              }
            }

          }
          catch (Exception ex)
          {
            switch (mErrorManager.ErrorMode)
            {
              case ErrorMode.ThrowException:
                byPass = true;
                throw;
              case ErrorMode.IgnoreAndContinue:
                break;
              case ErrorMode.SaveAndContinue:
                ErrorInfo err = new ErrorInfo();
                err.mLineNumber = mAsyncReader.LineNumber;
                err.mExceptionInfo = ex;
                //              err.mColumnNumber = mColumnNum;
                err.mRecordString = currentLine;

                mErrorManager.AddError(err);
                break;
            }
          }
          finally
          {
            if (byPass == false)
            {
              currentLine = mAsyncReader.ReadNextLine();
              mLineNumber = mAsyncReader.LineNumber;
            }
          }
        }
        else
        {
          mLastRecord = null;


          if (mRecordInfo.mIgnoreLast > 0)
            mFooterText = mAsyncReader.RemainingText;

          try
          {
            mAsyncReader.Close();
          }
          catch
          {
          }

          return;
        }
      }
    }


    /// <include file='FileHelperAsyncEngine.docs.xml' path='doc/ReadNexts/*'/>
    public object[] ReadNexts(int numberOfRecords)
    {
      if (mAsyncReader == null)
        throw new BadUsageException("Before call ReadNext you must call BeginReadFile or BeginReadStream.");

      ArrayList arr = new ArrayList(numberOfRecords);

      for (int i = 0; i < numberOfRecords; i++)
      {
        ReadNextRecord();
        if (mLastRecord != null)
          arr.Add(mLastRecord);
        else
          break;
      }
      return (object[])  arr.ToArray(RecordType);
    }

    #endregion
    
    #region "  IEnumerable implementation  "

     /// <summary>Allows to loop record by record in the engine</summary>
     /// <returns>The Enumerator</returns>
    IEnumerator IEnumerable.GetEnumerator()
    {
      if (mAsyncReader == null)
        throw new FileHelpersException("You must call BeginRead before use the engine in a foreach loop.");

      return new AsyncEnumerator(this);
    }
     
    private class AsyncEnumerator : IEnumerator
    {
      MultiRecordEngine mEngine;

      public AsyncEnumerator(MultiRecordEngine engine)
      {
        mEngine = engine;
      }

      public bool MoveNext()
      {
        object res = mEngine.ReadNext();
        
        if (res == null)
        {
          mEngine.Close();
          return false;
        }

        return true;

      }

      public object Current
      {
        get
        {
          return mEngine.mLastRecord;
        }
      }

      public void Reset()
      {
        // No needed
      }
    }

     
    #endregion

    #region "  IDisposable implementation  "
    
        /// <summary>
        /// Release Resources
        /// </summary>
    void IDisposable.Dispose()
    {
      Close();
      GC.SuppressFinalize(this);
    }
     
    /// <summary>Destructor</summary>
    ~MultiRecordEngine()
    {
      Close();
    }

    #endregion


    #region "  WriteNext  "
    /// <summary>Write the next record to a file or stream opened with <see cref="BeginWriteFile" />, <see cref="BeginWriteStream" /> or <see cref="BeginAppendToFile" /> method.</summary>
    /// <param name="record">The record to write.</param>
    public void WriteNext(object record)
    {
      if (mAsyncWriter == null)
        throw new BadUsageException("Before call WriteNext you must call BeginWriteFile or BeginWriteStream.");

      if (record == null)
        throw new BadUsageException("The record to write cant be null.");

      WriteRecord(record);
    }
    
    /// <summary>Write the nexts records to a file or stream opened with <see cref="BeginWriteFile" />, <see cref="BeginWriteStream" /> or <see cref="BeginAppendToFile" /> method.</summary>
    /// <param name="records">The records to write (Can be an array, ArrayList, etc)</param>
    public void WriteNexts(IEnumerable records)
    {
      if (mAsyncWriter == null)
        throw new BadUsageException("Before call WriteNext you must call BeginWriteFile or BeginWriteStream.");

      if (records == null)
        throw new ArgumentNullException("The record to write cant be null.");

      int nro = 0;
      foreach (object rec in records)
      {
        nro++;

        if (rec == null)
          throw new BadUsageException("The record at index " + nro.ToString() + " is null.");

        WriteRecord(rec);
      }
    }







    private void WriteRecord(object record)
    {
      string currentLine = null;

      try
      {
        bool skip = false;
//#if !MINI
//        ProgressHelper.Notify(mNotifyHandler, mProgressMode, i+1, max);
//        skip = OnBeforeWriteRecord(records[i]);
//#endif

        mLineNumber++;
        mTotalRecords++;

        RecordInfo info = (RecordInfo) mRecordInfoHash[record.GetType()];

        if (info == null)
          throw new BadUsageException("A record is of type '" + record.GetType().Name+ "' and the engine dont handle this type. You can add it to the constructor.");

        if (skip == false)
        {
          currentLine = info.RecordToString(record);
          mAsyncWriter.WriteLine(currentLine);
        }

      }
      catch (Exception ex)
      {
        switch (mErrorManager.ErrorMode)
        {
          case ErrorMode.ThrowException:
            throw;
          case ErrorMode.IgnoreAndContinue:
            break;
          case ErrorMode.SaveAndContinue:
            ErrorInfo err = new ErrorInfo();
            err.mLineNumber = mLineNumber;
            err.mExceptionInfo = ex;
            //              err.mColumnNumber = mColumnNum;
            err.mRecordString = currentLine;
            mErrorManager.AddError(err);
            break;
        }
      }


    }

    #endregion




    #region "  BeginWriteStream"

    ///  <summary>Set the stream to be used in the <see cref="WriteNext" /> operation.</summary>
    ///  <remarks><para>When you finish to write to the file you must call <b><see cref="Close" /></b> method.</para></remarks>
    ///  <param name="writer">To stream to writes to.</param>
    public void BeginWriteStream(TextWriter writer)
    {
      if (writer == null)
        throw new ArgumentException("writer", "The TextWriter cant be null.");

      ResetFields();
      mAsyncWriter = writer;
      WriteHeader();
    }

    private void WriteHeader()
    {
      if (mHeaderText != null && mHeaderText != string.Empty)
        if (mHeaderText.EndsWith(StringHelper.NewLine))
          mAsyncWriter.Write(mHeaderText);
        else
          mAsyncWriter.WriteLine(mHeaderText);
    }

    #endregion

    #region "  BeginWriteFile  "

    ///  <summary>Open a file for write operations. If exist the engine override it. You can use <see cref="WriteNext"/> or <see cref="WriteNexts"/> to write records.</summary>
    ///  <remarks><para>When you finish to write to the file you must call <b><see cref="Close" /></b> method.</para></remarks>
    /// <param name="fileName">The file path to be opened for write.</param>
    public void BeginWriteFile(string fileName)
    {
      BeginWriteStream(new StreamWriter(fileName, false, mEncoding));
    }

    #endregion


    #region "  BeginappendToFile  "

    ///  <summary>Open a file to be appended at the end.</summary>
    ///  <remarks><para>This method open and seek to the end the file.</para>
    ///  <para>When you finish to append to the file you must call <b><see cref="Close" /></b> method.</para></remarks>
    ///  <param name="fileName">The file path to be opened to write at the end.</param>
    public void BeginAppendToFile(string fileName)
    {
      mAsyncWriter = StreamHelper.CreateFileAppender(fileName, mEncoding, false);
      mHeaderText = String.Empty;
      mFooterText = String.Empty;
    }

    #endregion

  }
}

//#endif
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.