init
This commit is contained in:
193
Common/DTS.Common.Utilities/FileMapViewArray.cs
Normal file
193
Common/DTS.Common.Utilities/FileMapViewArray.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using DTS.Common.Utilities;
|
||||
using DTS.Common.Utilities.Logging;
|
||||
|
||||
namespace DTS.Common.Utilities.IO.MemoryMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows a view of a memory mapped file
|
||||
/// to be accessed via the index[] operator.
|
||||
/// </summary>
|
||||
public class FileMapViewArray : IDisposable
|
||||
{
|
||||
#region privates
|
||||
const long systemOffsetSize = 65536;
|
||||
protected Stream _view;
|
||||
protected MemoryMappedFile _file;
|
||||
protected MapAccess _mapAccess;
|
||||
protected byte[] buffer;
|
||||
|
||||
protected long _mapSize;
|
||||
protected long _offsetOfViewFromStartOfMap;
|
||||
protected int _viewSize;
|
||||
|
||||
void ResetView(long newViewStart)
|
||||
{
|
||||
// Make sure we scale the last view of the file to not overrun the end.
|
||||
var newViewSize =
|
||||
_mapSize - newViewStart > _viewSize ?
|
||||
_viewSize :
|
||||
(int)(_mapSize - newViewStart);
|
||||
|
||||
if (newViewSize < 1)
|
||||
newViewSize = 0x100;
|
||||
|
||||
// Moves the view if we reach the end.
|
||||
_view.Close();
|
||||
_view = _file.MapView(_mapAccess, newViewStart, newViewSize);
|
||||
_offsetOfViewFromStartOfMap = newViewStart;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region public
|
||||
/// <summary>
|
||||
/// Clears all buffers for the stream and causes
|
||||
/// any unbuffered data to be written to the
|
||||
/// underlying device.
|
||||
/// </summary>
|
||||
public void forceFlush()
|
||||
{
|
||||
_view.Flush();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Indexor
|
||||
/// <summary>
|
||||
/// Returns a the byte at the requested index of the MemoryMap.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public byte this[long index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index >= _mapSize || index < 0)
|
||||
throw new Exception("Index is out of range.");
|
||||
|
||||
try
|
||||
{
|
||||
// Get us to the right place
|
||||
var position = index - _offsetOfViewFromStartOfMap;
|
||||
if (position < _view.Length && position >= 0)
|
||||
{
|
||||
_view.Seek(position, SeekOrigin.Begin);
|
||||
return (byte)_view.ReadByte();
|
||||
}
|
||||
}
|
||||
catch (FileMapIOException)
|
||||
{
|
||||
}
|
||||
// We overran the view; move it:
|
||||
// Overunning means index is one (or more) greater (or less) than the greatest
|
||||
// 'valid' index, so we need to refocus to one back from where we are now.
|
||||
// Reset the view to the page containing the out-of-bounds index.
|
||||
|
||||
//this.ResetView(index);
|
||||
ResetView(index / systemOffsetSize * systemOffsetSize);
|
||||
// Try again.
|
||||
return this[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
try
|
||||
{
|
||||
_view.Seek(index, SeekOrigin.Begin);
|
||||
_view.WriteByte(value);
|
||||
}
|
||||
catch (FileMapIOException)
|
||||
{
|
||||
ResetView(index);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Master Constructor
|
||||
/// This constructor allows for specifying privilages
|
||||
/// for the stream and mapped file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">File from which to create mapping</param>
|
||||
/// <param name="access">Access level for the map view in memory. Must be consisten with the file mapping access.</param>
|
||||
/// <param name="protection">Access level for the file mapping.</param>
|
||||
/// <param name="fileMapSize">The size in bytes of the file mapping. Pass 0 to map the entire (existing and length>0) file.</param>
|
||||
/// <param name="offset">Off set from start of mapped file to start the view.</param>
|
||||
/// <param name="viewSize">The size of the view in memory. This is limited by physical system resources.</param>
|
||||
public FileMapViewArray(string fileName, MapAccess access, MapProtection protection, ulong offset, long fileMapSize, int viewSize)
|
||||
{
|
||||
long mapSize;
|
||||
//Check file exists and length > 0;
|
||||
if (File.Exists(fileName) && new FileInfo(Path.GetFullPath(fileName)).Length != 0)
|
||||
//passing 0 will map the whole file
|
||||
mapSize =
|
||||
fileMapSize != 0 ? fileMapSize : Path.GetFullPath(fileName).Length;
|
||||
|
||||
else //file didn't exist or length==0, doesn't matter, gotta create it with correct size
|
||||
{
|
||||
//can't pass 0 here
|
||||
if (fileMapSize == 0) throw new Exception("Cannot map an empty or non-existent file.");
|
||||
else
|
||||
{
|
||||
// fileMapSize used here just to get a file
|
||||
// with a non-trivial size.
|
||||
File.Create(fileName, (int)fileMapSize);
|
||||
//a value was passed for the size of the map
|
||||
mapSize = fileMapSize;
|
||||
}
|
||||
}
|
||||
|
||||
var map =
|
||||
MemoryMappedFile.Create(fileName, protection, mapSize);
|
||||
|
||||
var view = map.MapView(access, (long)(offset / systemOffsetSize * systemOffsetSize), (int)System.Math.Min(mapSize, viewSize));
|
||||
|
||||
buffer = new byte[1];
|
||||
_mapAccess = access;
|
||||
_viewSize = viewSize;
|
||||
|
||||
_mapSize = mapSize;
|
||||
_file = map;
|
||||
_view = view;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
//this._file.Close(); // RW 2896 - added close to dispose
|
||||
//CPB DM - this should happen post view flush()
|
||||
|
||||
// flush view then close file.
|
||||
_view.Flush();
|
||||
|
||||
_file.Close();
|
||||
|
||||
_view.Close();
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
APILogger.Log(ex);
|
||||
//the stream was probably closed by .NET
|
||||
}
|
||||
_view.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user