using System; using System.IO; using System.Collections; namespace Be.Windows.Forms { /// /// Byte provider for (big) files. /// public class FileByteProvider : IByteProvider, IDisposable { #region WriteCollection class /// /// Represents the write buffer class /// class WriteCollection : DictionaryBase { /// /// Gets or sets a byte in the collection /// public byte this[long index] { get { return (byte)this.Dictionary[index]; } set { Dictionary[index] = value; } } /// /// Adds a byte into the collection /// /// the index of the byte /// the value of the byte public void Add(long index, byte value) { Dictionary.Add(index, value); } /// /// Determines if a byte with the given index exists. /// /// the index of the byte /// true, if the is in the collection public bool Contains(long index) { return Dictionary.Contains(index); } } #endregion /// /// Occurs, when the write buffer contains new changes. /// public event EventHandler Changed; /// /// Contains all changes /// WriteCollection _writes = new WriteCollection(); /// /// Contains the file name. /// string _fileName; /// /// Contains the file stream. /// FileStream _fileStream; /// /// Read-only access. /// bool _readOnly; /// /// Initializes a new instance of the FileByteProvider class. /// /// public FileByteProvider(string fileName) { _fileName = fileName; try { // try to open in write mode _fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); } catch { // write mode failed, try to open in read-only and fileshare friendly mode. try { _fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); _readOnly = true; } catch { throw; } } } /// /// Terminates the instance of the FileByteProvider class. /// ~FileByteProvider() { Dispose(); } /// /// Raises the Changed event. /// /// Never used. void OnChanged(EventArgs e) { if(Changed != null) Changed(this, e); } /// /// Gets the name of the file the byte provider is using. /// public string FileName { get { return _fileName; } } /// /// Returns a value if there are some changes. /// /// true, if there are some changes public bool HasChanges() { return (_writes.Count > 0); } /// /// Updates the file with all changes the write buffer contains. /// public void ApplyChanges() { if (this._readOnly) { throw new Exception("File is in read-only mode."); } if(!HasChanges()) return; IDictionaryEnumerator en = _writes.GetEnumerator(); while(en.MoveNext()) { long index = (long)en.Key; byte value = (byte)en.Value; if(_fileStream.Position != index) _fileStream.Position = index; _fileStream.Write(new byte[] { value }, 0, 1); } _writes.Clear(); } /// /// Clears the write buffer and reject all changes made. /// public void RejectChanges() { _writes.Clear(); } #region IByteProvider Members /// /// Never used. /// public event EventHandler LengthChanged; /// /// Never Used /// /// Event Args protected virtual void OnLengthChanged (EventArgs e) { if (LengthChanged != null) LengthChanged(this, e); } /// /// Reads a byte from the file. /// /// the index of the byte to read /// the byte public byte ReadByte(long index) { if(_writes.Contains(index)) return _writes[index]; if(_fileStream.Position != index) _fileStream.Position = index; byte res = (byte)_fileStream.ReadByte(); return res; } /// /// Gets the length of the file. /// public long Length { get { return _fileStream.Length; } } /// /// Writes a byte into write buffer /// public void WriteByte(long index, byte value) { if(_writes.Contains(index)) _writes[index] = value; else _writes.Add(index, value); OnChanged(EventArgs.Empty); } /// /// Not supported /// public void DeleteBytes(long index, long length) { throw new NotSupportedException("FileByteProvider.DeleteBytes"); } /// /// Not supported /// public void InsertBytes(long index, byte[] bs) { throw new NotSupportedException("FileByteProvider.InsertBytes"); } /// /// Returns true /// public bool SupportsWriteByte() { return !_readOnly; } /// /// Returns false /// public bool SupportsInsertBytes() { return false; } /// /// Returns false /// public bool SupportsDeleteBytes() { return false; } #endregion #region IDisposable Members /// /// Releases the file handle used by the FileByteProvider. /// public void Dispose() { if(_fileStream != null) { _fileName = null; _fileStream.Close(); _fileStream = null; } GC.SuppressFinalize(this); } #endregion } }