//******************************************************************************************************// IsamDataFileBase.cs - Gbtc//// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/MIT//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 03/08/2007 - Pinal C. Patel// Original version of source code generated.// 11/30/2007 - Pinal C. Patel// Modified the "design time" check in EndInit() method to use LicenseManager.UsageMode property// instead of DesignMode property as the former is more accurate than the latter.// 09/19/2008 - J. Ritchie Carroll// Converted to C#.// 10/28/2008 - Pinal C. Patel// Edited code comments.// 12/04/2008 - J. Ritchie Carroll// Modified class an example to use new ISupportBinaryImage.// 05/12/2009 - Pinal C. Patel// Optimized Read() for better memory management by using "yield return".// 05/19/2009 - Pinal C. Patel// Implemented the IProvideStatus interface.// 07/02/2009 - Pinal C. Patel// Modified state alternating properties to reopen the file when changed.// 08/10/2009 - Pinal C. Patel// Modified Write() to write empty intermediate records that are missing to avoid garbage data // for the missing intermediate records when records are being written to disk directly.// 09/14/2009 - Stephen C. Wills// Added new header and license agreement.// 09/16/2009 - Pinal C. Patel// Modified Save() to flush buffered data to disk.// Removed MinimumRecordCount property - not very useful.// 09/17/2009 - Pinal C. Patel// Added exception handling to event handlers.// 12/04/2009 - Pinal C. Patel// Fixed thread synchronization issue in ReadFromDisk().// 04/07/2011 - Pinal C. Patel// Removed inheritance from Component class to allow for serialization.// 11/23/2011 - J. Ritchie Carroll// Modified to support buffer optimized ISupportBinaryImage.// 12/06/2011 - Pinal C. Patel// Updated to instantiate a FileSystemWatcher object that watches for changes to the file content // only if needed to avoid a issue introduced in .NET 4.0 that causes memory leak.// 12/14/2012 - Starlynn Danyelle Gilliam// Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Configuration;using System.IO;using System.Text;using System.Threading;using System.Timers;using System.Xml.Serialization;using GSF.Configuration;using GSF.Parsing;using Timer = System.Timers.Timer; namespace GSF.IO{ /// <summary> /// An abstract class that defines the read/write capabilities for ISAM (Indexed Sequential Access Method) file. /// </summary> /// <typeparam name="T"> /// <see cref="Type"/> of the records the file contains. This <see cref="Type"/> must implement the <see cref="ISupportBinaryImage"/> interface. /// </typeparam> /// <remarks> /// <para> /// This ISAM implementation keeps all the records in memory, so it may not be suitable for very large files. Since data is stored /// in memory using a list, the maximum number of possible supported records will be 2,147,483,647 (i.e., Int32.MaxValue). /// </para> /// <para> /// See <a href="http://en.wikipedia.org/wiki/ISAM" target="_blank">http://en.wikipedia.org/wiki/ISAM</a> for more information on ISAM files. /// </para> /// </remarks> /// <example> /// This example shows a sample implementation of <see cref="IsamDataFileBase{T}"/>: /// <code> /// using System; /// using System.Text; /// using GSF; /// using GSF.IO; /// using GSF.Parsing; /// /// class Program /// { /// static void Main(string[] args) /// { /// // Create a few test records. /// TestIsamFileRecord r1 = new TestIsamFileRecord(1); /// r1.Name = "TestRecord1"; /// r1.Value = double.MinValue; /// r1.Description = "Test record with minimum double value"; /// TestIsamFileRecord r2 = new TestIsamFileRecord(2); /// r2.Name = "TestRecord2"; /// r2.Value = double.MaxValue; /// r2.Description = "Test record with maximum double value"; /// /// // Open ISAM file. /// TestIsamFile testFile = new TestIsamFile(); /// testFile.FileName = "TestIsamFile.dat"; /// testFile.Open(); /// /// // Write test records. /// testFile.Write(r1.Index, r1); /// testFile.Write(r2.Index, r2); /// /// // Read test records. /// Console.WriteLine(testFile.Read(1)); /// Console.WriteLine(testFile.Read(2)); /// /// // Close ISAM file. /// testFile.Close(); /// /// Console.ReadLine(); /// } /// } /// /// class TestIsamFile : IsamDataFileBase<TestIsamFileRecord> /// { /// /// <summary> /// /// Size of a single file record. /// /// </summary> /// protected override int GetRecordSize() /// { /// return TestIsamFileRecord.RecordLength; /// } /// /// /// <summary> /// /// Creates a new empty file record. /// /// </summary> /// protected override TestIsamFileRecord CreateNewRecord(int id) /// { /// return new TestIsamFileRecord(id); /// } /// } /// /// class TestIsamFileRecord : ISupportBinaryImage /// { /// private int m_index; /// private string m_name; // 20 * 1 = 20 /// private double m_value; // 1 * 8 = 8 /// private string m_description; // 100 * 1 = 100 /// /// public const int RecordLength = 128; // Total = 128 /// /// public TestIsamFileRecord(int recordIndex) /// { /// m_index = recordIndex; /// /// Name = string.Empty; /// Value = double.NaN; /// Description = string.Empty; /// } /// /// /// <summary> /// /// 1-based index of the record. /// /// </summary> /// public int Index /// { /// get { return m_index; } /// } /// /// /// <summary> /// /// Name of the record. /// /// </summary> /// public string Name /// { /// get { return m_name; } /// set { m_name = value.TruncateRight(20).PadRight(20); } /// } /// /// /// <summary> /// /// Value of the record. /// /// </summary> /// public double Value /// { /// get { return m_value; } /// set { m_value = value; } /// } /// /// /// <summary> /// /// Description of the record. /// /// </summary> /// public string Description /// { /// get { return m_description; } /// set { m_description = value.TruncateRight(100).PadRight(100); } /// } /// /// /// <summary> /// /// Serialized record length. /// /// </summary> /// public int BinaryLength /// { /// get { return RecordLength; } /// } /// /// /// <summary> /// /// Serialized record data. /// /// </summary> /// public byte[] BinaryImage /// { /// get /// { /// // Serialize TestIsamFileRecord into byte array. /// byte[] image = new byte[RecordLength]; /// Buffer.BlockCopy(Encoding.ASCII.GetBytes(Name), 0, image, 0, 20); /// Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, image, 20, 8); /// Buffer.BlockCopy(Encoding.ASCII.GetBytes(Description), 0, image, 28, 100); /// /// return image; /// } /// } /// /// /// <summary> /// /// Deserializes the record. /// /// </summary> /// public int Initialize(byte[] binaryImage, int startIndex, int length) /// { /// if (length >= RecordLength) /// { /// // Deserialize byte array into TestIsamFileRecord. /// Name = Encoding.ASCII.GetString(binaryImage, startIndex, 20); /// Value = BitConverter.ToDouble(binaryImage, startIndex + 20); /// Description = Encoding.ASCII.GetString(binaryImage, startIndex + 28, 100); /// } /// else /// throw new InvalidOperationException("Invalid record size, not enough data to deserialize record"); /// /// return RecordLength; /// } /// /// /// <summary> /// /// String representation of the record. /// /// </summary> /// public override string ToString() /// { /// return string.Format("Name: {0}, Value: {1}, Description: {2}", Name, Value, Description); /// } /// } /// </code> /// </example> public abstract class IsamDataFileBase<T> : ISupportLifecycle, IProvideStatus, IPersistSettings where T : ISupportBinaryImage { #region [ Members ] // Constants /// <summary> /// Specifies the default value for the <see cref="FileName"/> property. /// </summary> public const string DefaultFileName = "IsamDataFile.dat"; /// <summary> /// Specifies the default value for the <see cref="FileAccessMode"/> property. /// </summary> public const FileAccess DefaultFileAccessMode = FileAccess.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="AutoSaveInterval"/> property. /// </summary> public const int DefaultAutoSaveInterval = -1; /// <summary> /// Specifies the default value for the <see cref="LoadOnOpen"/> property. /// </summary> public const bool DefaultLoadOnOpen = false; /// <summary> /// Specifies the default value for the <see cref="SaveOnClose"/> property. /// </summary> public const bool DefaultSaveOnClose = false; /// <summary> /// Specifies the default value for the <see cref="ReloadOnModify"/> property. /// </summary> public const bool DefaultReloadOnModify = false; /// <summary> /// Specifies the default value for the <see cref="PersistSettings"/> property. /// </summary> public const bool DefaultPersistSettings = false; /// <summary> /// Specifies the default value for the <see cref="SettingsCategory"/> property. /// </summary> public const string DefaultSettingsCategory = "IsamDataFile"; // Events /// <summary> /// Occurs when data is being read from disk into memory. /// </summary> public event EventHandler DataLoading; /// <summary> /// Occurs when data has been read from disk into memory. /// </summary> public event EventHandler DataLoaded; /// <summary> /// Occurs when data is being saved from memory onto disk. /// </summary> public event EventHandler DataSaving; /// <summary> /// Occurs when data has been saved from memory onto disk. /// </summary> public event EventHandler DataSaved; /// <summary> /// Occurs when file data on the disk is modified. /// </summary> public event EventHandler FileModified; /// <summary> /// Occurs when the class has been disposed. /// </summary> public event EventHandler Disposed; // Fields private string m_fileName; private FileAccess m_fileAccessMode; private int m_autoSaveInterval; private bool m_loadOnOpen; private bool m_saveOnClose; private bool m_reloadOnModify; private bool m_persistSettings; private string m_settingsCategory; private List<T> m_fileRecords; private byte[] m_recordBuffer; private FileStream m_fileData; private readonly object m_fileDataLock; private readonly ManualResetEventSlim m_loadWaitHandle; private readonly ManualResetEventSlim m_saveWaitHandle; private readonly Timer m_autoSaveTimer; private SafeFileWatcher m_fileWatcher; private bool m_disposed; private bool m_initialized; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="IsamDataFileBase{T}"/> class. /// </summary> protected IsamDataFileBase() { m_fileName = DefaultFileName; m_fileAccessMode = DefaultFileAccessMode; m_autoSaveInterval = DefaultAutoSaveInterval; m_loadOnOpen = DefaultLoadOnOpen; m_saveOnClose = DefaultSaveOnClose; m_reloadOnModify = DefaultReloadOnModify; m_persistSettings = DefaultPersistSettings; m_settingsCategory = DefaultSettingsCategory; m_loadWaitHandle = new ManualResetEventSlim(true); m_saveWaitHandle = new ManualResetEventSlim(true); m_fileDataLock = new object(); m_autoSaveTimer = new Timer(); m_autoSaveTimer.Elapsed += m_autoSaveTimer_Elapsed; } /// <summary> /// Releases the unmanaged resources before the file is reclaimed by <see cref="GC"/>. /// </summary> ~IsamDataFileBase() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets or sets the name of the file. /// </summary> /// <remarks> /// Changing the <see cref="FileName"/> when the file is open will cause the file to be re-opened. /// </remarks> public virtual string FileName { get { return m_fileName; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); m_fileName = value; ReOpen(); } } /// <summary> /// Gets or sets the <see cref="FileAccess"/> value to use when opening the file. /// </summary> public FileAccess FileAccessMode { get { return m_fileAccessMode; } set { m_fileAccessMode = value; ReOpen(); } } /// <summary> /// Gets or sets the interval in milliseconds at which the records loaded in memory are to be persisted to disk. /// </summary> /// <remarks> /// <see cref="AutoSaveInterval"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public int AutoSaveInterval { get { return m_autoSaveInterval; } set { m_autoSaveInterval = value; ReOpen(); } } /// <summary> /// Gets or sets a boolean value that indicates whether records are to be loaded automatically in memory when /// the file is opened. /// </summary> public bool LoadOnOpen { get { return m_loadOnOpen; } set { m_loadOnOpen = value; ReOpen(); } } /// <summary> /// Gets or sets a boolean value that indicates whether records loaded in memory are to be persisted to disk /// when the file is closed. /// </summary> /// <remarks> /// <see cref="SaveOnClose"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public bool SaveOnClose { get { return m_saveOnClose; } set { m_saveOnClose = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether records loaded in memory are to be re-loaded when the /// file is modified on disk. /// </summary> /// <remarks> /// <see cref="ReloadOnModify"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public bool ReloadOnModify { get { return m_reloadOnModify; }Lines 1–500 of 1408. Load more
//****************************************************************************************************** // IsamDataFileBase.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 03/08/2007 - Pinal C. Patel // Original version of source code generated. // 11/30/2007 - Pinal C. Patel // Modified the "design time" check in EndInit() method to use LicenseManager.UsageMode property // instead of DesignMode property as the former is more accurate than the latter. // 09/19/2008 - J. Ritchie Carroll // Converted to C#. // 10/28/2008 - Pinal C. Patel // Edited code comments. // 12/04/2008 - J. Ritchie Carroll // Modified class an example to use new ISupportBinaryImage. // 05/12/2009 - Pinal C. Patel // Optimized Read() for better memory management by using "yield return". // 05/19/2009 - Pinal C. Patel // Implemented the IProvideStatus interface. // 07/02/2009 - Pinal C. Patel // Modified state alternating properties to reopen the file when changed. // 08/10/2009 - Pinal C. Patel // Modified Write() to write empty intermediate records that are missing to avoid garbage data // for the missing intermediate records when records are being written to disk directly. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 09/16/2009 - Pinal C. Patel // Modified Save() to flush buffered data to disk. // Removed MinimumRecordCount property - not very useful. // 09/17/2009 - Pinal C. Patel // Added exception handling to event handlers. // 12/04/2009 - Pinal C. Patel // Fixed thread synchronization issue in ReadFromDisk(). // 04/07/2011 - Pinal C. Patel // Removed inheritance from Component class to allow for serialization. // 11/23/2011 - J. Ritchie Carroll // Modified to support buffer optimized ISupportBinaryImage. // 12/06/2011 - Pinal C. Patel // Updated to instantiate a FileSystemWatcher object that watches for changes to the file content // only if needed to avoid a issue introduced in .NET 4.0 that causes memory leak. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Text; using System.Threading; using System.Timers; using System.Xml.Serialization; using GSF.Configuration; using GSF.Parsing; using Timer = System.Timers.Timer; namespace GSF.IO { /// <summary> /// An abstract class that defines the read/write capabilities for ISAM (Indexed Sequential Access Method) file. /// </summary> /// <typeparam name="T"> /// <see cref="Type"/> of the records the file contains. This <see cref="Type"/> must implement the <see cref="ISupportBinaryImage"/> interface. /// </typeparam> /// <remarks> /// <para> /// This ISAM implementation keeps all the records in memory, so it may not be suitable for very large files. Since data is stored /// in memory using a list, the maximum number of possible supported records will be 2,147,483,647 (i.e., Int32.MaxValue). /// </para> /// <para> /// See <a href="http://en.wikipedia.org/wiki/ISAM" target="_blank">http://en.wikipedia.org/wiki/ISAM</a> for more information on ISAM files. /// </para> /// </remarks> /// <example> /// This example shows a sample implementation of <see cref="IsamDataFileBase{T}"/>: /// <code> /// using System; /// using System.Text; /// using GSF; /// using GSF.IO; /// using GSF.Parsing; /// /// class Program /// { /// static void Main(string[] args) /// { /// // Create a few test records. /// TestIsamFileRecord r1 = new TestIsamFileRecord(1); /// r1.Name = "TestRecord1"; /// r1.Value = double.MinValue; /// r1.Description = "Test record with minimum double value"; /// TestIsamFileRecord r2 = new TestIsamFileRecord(2); /// r2.Name = "TestRecord2"; /// r2.Value = double.MaxValue; /// r2.Description = "Test record with maximum double value"; /// /// // Open ISAM file. /// TestIsamFile testFile = new TestIsamFile(); /// testFile.FileName = "TestIsamFile.dat"; /// testFile.Open(); /// /// // Write test records. /// testFile.Write(r1.Index, r1); /// testFile.Write(r2.Index, r2); /// /// // Read test records. /// Console.WriteLine(testFile.Read(1)); /// Console.WriteLine(testFile.Read(2)); /// /// // Close ISAM file. /// testFile.Close(); /// /// Console.ReadLine(); /// } /// } /// /// class TestIsamFile : IsamDataFileBase<TestIsamFileRecord> /// { /// /// <summary> /// /// Size of a single file record. /// /// </summary> /// protected override int GetRecordSize() /// { /// return TestIsamFileRecord.RecordLength; /// } /// /// /// <summary> /// /// Creates a new empty file record. /// /// </summary> /// protected override TestIsamFileRecord CreateNewRecord(int id) /// { /// return new TestIsamFileRecord(id); /// } /// } /// /// class TestIsamFileRecord : ISupportBinaryImage /// { /// private int m_index; /// private string m_name; // 20 * 1 = 20 /// private double m_value; // 1 * 8 = 8 /// private string m_description; // 100 * 1 = 100 /// /// public const int RecordLength = 128; // Total = 128 /// /// public TestIsamFileRecord(int recordIndex) /// { /// m_index = recordIndex; /// /// Name = string.Empty; /// Value = double.NaN; /// Description = string.Empty; /// } /// /// /// <summary> /// /// 1-based index of the record. /// /// </summary> /// public int Index /// { /// get { return m_index; } /// } /// /// /// <summary> /// /// Name of the record. /// /// </summary> /// public string Name /// { /// get { return m_name; } /// set { m_name = value.TruncateRight(20).PadRight(20); } /// } /// /// /// <summary> /// /// Value of the record. /// /// </summary> /// public double Value /// { /// get { return m_value; } /// set { m_value = value; } /// } /// /// /// <summary> /// /// Description of the record. /// /// </summary> /// public string Description /// { /// get { return m_description; } /// set { m_description = value.TruncateRight(100).PadRight(100); } /// } /// /// /// <summary> /// /// Serialized record length. /// /// </summary> /// public int BinaryLength /// { /// get { return RecordLength; } /// } /// /// /// <summary> /// /// Serialized record data. /// /// </summary> /// public byte[] BinaryImage /// { /// get /// { /// // Serialize TestIsamFileRecord into byte array. /// byte[] image = new byte[RecordLength]; /// Buffer.BlockCopy(Encoding.ASCII.GetBytes(Name), 0, image, 0, 20); /// Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, image, 20, 8); /// Buffer.BlockCopy(Encoding.ASCII.GetBytes(Description), 0, image, 28, 100); /// /// return image; /// } /// } /// /// /// <summary> /// /// Deserializes the record. /// /// </summary> /// public int Initialize(byte[] binaryImage, int startIndex, int length) /// { /// if (length >= RecordLength) /// { /// // Deserialize byte array into TestIsamFileRecord. /// Name = Encoding.ASCII.GetString(binaryImage, startIndex, 20); /// Value = BitConverter.ToDouble(binaryImage, startIndex + 20); /// Description = Encoding.ASCII.GetString(binaryImage, startIndex + 28, 100); /// } /// else /// throw new InvalidOperationException("Invalid record size, not enough data to deserialize record"); /// /// return RecordLength; /// } /// /// /// <summary> /// /// String representation of the record. /// /// </summary> /// public override string ToString() /// { /// return string.Format("Name: {0}, Value: {1}, Description: {2}", Name, Value, Description); /// } /// } /// </code> /// </example> public abstract class IsamDataFileBase<T> : ISupportLifecycle, IProvideStatus, IPersistSettings where T : ISupportBinaryImage { #region [ Members ] // Constants /// <summary> /// Specifies the default value for the <see cref="FileName"/> property. /// </summary> public const string DefaultFileName = "IsamDataFile.dat"; /// <summary> /// Specifies the default value for the <see cref="FileAccessMode"/> property. /// </summary> public const FileAccess DefaultFileAccessMode = FileAccess.ReadWrite; /// <summary> /// Specifies the default value for the <see cref="AutoSaveInterval"/> property. /// </summary> public const int DefaultAutoSaveInterval = -1; /// <summary> /// Specifies the default value for the <see cref="LoadOnOpen"/> property. /// </summary> public const bool DefaultLoadOnOpen = false; /// <summary> /// Specifies the default value for the <see cref="SaveOnClose"/> property. /// </summary> public const bool DefaultSaveOnClose = false; /// <summary> /// Specifies the default value for the <see cref="ReloadOnModify"/> property. /// </summary> public const bool DefaultReloadOnModify = false; /// <summary> /// Specifies the default value for the <see cref="PersistSettings"/> property. /// </summary> public const bool DefaultPersistSettings = false; /// <summary> /// Specifies the default value for the <see cref="SettingsCategory"/> property. /// </summary> public const string DefaultSettingsCategory = "IsamDataFile"; // Events /// <summary> /// Occurs when data is being read from disk into memory. /// </summary> public event EventHandler DataLoading; /// <summary> /// Occurs when data has been read from disk into memory. /// </summary> public event EventHandler DataLoaded; /// <summary> /// Occurs when data is being saved from memory onto disk. /// </summary> public event EventHandler DataSaving; /// <summary> /// Occurs when data has been saved from memory onto disk. /// </summary> public event EventHandler DataSaved; /// <summary> /// Occurs when file data on the disk is modified. /// </summary> public event EventHandler FileModified; /// <summary> /// Occurs when the class has been disposed. /// </summary> public event EventHandler Disposed; // Fields private string m_fileName; private FileAccess m_fileAccessMode; private int m_autoSaveInterval; private bool m_loadOnOpen; private bool m_saveOnClose; private bool m_reloadOnModify; private bool m_persistSettings; private string m_settingsCategory; private List<T> m_fileRecords; private byte[] m_recordBuffer; private FileStream m_fileData; private readonly object m_fileDataLock; private readonly ManualResetEventSlim m_loadWaitHandle; private readonly ManualResetEventSlim m_saveWaitHandle; private readonly Timer m_autoSaveTimer; private SafeFileWatcher m_fileWatcher; private bool m_disposed; private bool m_initialized; #endregion #region [ Constructors ] /// <summary> /// Initializes a new instance of the <see cref="IsamDataFileBase{T}"/> class. /// </summary> protected IsamDataFileBase() { m_fileName = DefaultFileName; m_fileAccessMode = DefaultFileAccessMode; m_autoSaveInterval = DefaultAutoSaveInterval; m_loadOnOpen = DefaultLoadOnOpen; m_saveOnClose = DefaultSaveOnClose; m_reloadOnModify = DefaultReloadOnModify; m_persistSettings = DefaultPersistSettings; m_settingsCategory = DefaultSettingsCategory; m_loadWaitHandle = new ManualResetEventSlim(true); m_saveWaitHandle = new ManualResetEventSlim(true); m_fileDataLock = new object(); m_autoSaveTimer = new Timer(); m_autoSaveTimer.Elapsed += m_autoSaveTimer_Elapsed; } /// <summary> /// Releases the unmanaged resources before the file is reclaimed by <see cref="GC"/>. /// </summary> ~IsamDataFileBase() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets or sets the name of the file. /// </summary> /// <remarks> /// Changing the <see cref="FileName"/> when the file is open will cause the file to be re-opened. /// </remarks> public virtual string FileName { get { return m_fileName; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); m_fileName = value; ReOpen(); } } /// <summary> /// Gets or sets the <see cref="FileAccess"/> value to use when opening the file. /// </summary> public FileAccess FileAccessMode { get { return m_fileAccessMode; } set { m_fileAccessMode = value; ReOpen(); } } /// <summary> /// Gets or sets the interval in milliseconds at which the records loaded in memory are to be persisted to disk. /// </summary> /// <remarks> /// <see cref="AutoSaveInterval"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public int AutoSaveInterval { get { return m_autoSaveInterval; } set { m_autoSaveInterval = value; ReOpen(); } } /// <summary> /// Gets or sets a boolean value that indicates whether records are to be loaded automatically in memory when /// the file is opened. /// </summary> public bool LoadOnOpen { get { return m_loadOnOpen; } set { m_loadOnOpen = value; ReOpen(); } } /// <summary> /// Gets or sets a boolean value that indicates whether records loaded in memory are to be persisted to disk /// when the file is closed. /// </summary> /// <remarks> /// <see cref="SaveOnClose"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public bool SaveOnClose { get { return m_saveOnClose; } set { m_saveOnClose = value; } } /// <summary> /// Gets or sets a boolean value that indicates whether records loaded in memory are to be re-loaded when the /// file is modified on disk. /// </summary> /// <remarks> /// <see cref="ReloadOnModify"/> will be effective only if records have been loaded in memory either manually /// by calling the <see cref="Load()"/> method or automatically by settings <see cref="LoadOnOpen"/> to true. /// </remarks> public bool ReloadOnModify { get { return m_reloadOnModify; }