mirror of https://github.com/emgucv/emgucv.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
7.5 KiB
219 lines
7.5 KiB
//----------------------------------------------------------------------------
|
|
// Copyright (C) 2004-2012 by EMGU. All rights reserved.
|
|
//----------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Emgu.Util
|
|
{
|
|
/// <summary>
|
|
/// A raw data storage
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of elments in the storage</typeparam>
|
|
public class BinaryFileStorage<T> : IEnumerable<T> where T : struct
|
|
{
|
|
private static int _elementSize = Marshal.SizeOf(typeof(T));
|
|
|
|
private int _trunkSize;
|
|
|
|
private const int _defaultTrunkSize = 4096;
|
|
|
|
/// <summary>
|
|
/// The file info
|
|
/// </summary>
|
|
protected FileInfo _fileInfo;
|
|
|
|
/// <summary>
|
|
/// Create a binary File Storage
|
|
/// </summary>
|
|
/// <param name="fileName">The file name of the storage</param>
|
|
public BinaryFileStorage(String fileName)
|
|
: this(fileName, _defaultTrunkSize)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a binary File Storage
|
|
/// </summary>
|
|
/// <param name="fileName">The file name of the storage</param>
|
|
/// <param name="trunkSize">The data will be read in trunk of this size internally. Can be use to seed up the file read. A good number will be 4096</param>
|
|
public BinaryFileStorage(String fileName, int trunkSize)
|
|
{
|
|
_fileInfo = new FileInfo(fileName);
|
|
_trunkSize = trunkSize <= 0 ? _defaultTrunkSize : trunkSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a binary File Storage with the specific data
|
|
/// </summary>
|
|
/// <param name="fileName">The file name of the storage, all data in the existing file will be replaced</param>
|
|
/// <param name="samples">The data which will be stored in the storage</param>
|
|
public BinaryFileStorage(String fileName, IEnumerable<T> samples)
|
|
: this(fileName)
|
|
{
|
|
Clear();
|
|
Append(samples);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Delete all data in the existing storage, if there is any.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
if (_fileInfo.Exists)
|
|
_fileInfo.Delete();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append the samples to the end of the storage
|
|
/// </summary>
|
|
/// <param name="samples">The samples to be appended to the storage</param>
|
|
public void Append(IEnumerable<T> samples)
|
|
{
|
|
int elementsInTrunk = _trunkSize / _elementSize;
|
|
if (elementsInTrunk <= 0)
|
|
elementsInTrunk = 1;
|
|
|
|
byte[] byteBuffer = new byte[elementsInTrunk * _elementSize];
|
|
int index = 0;
|
|
using (PinnedArray<T> buffer = new PinnedArray<T>(elementsInTrunk))
|
|
using (FileStream stream = _fileInfo.Open(FileMode.Append, FileAccess.Write))
|
|
using (BufferedStream bufferStream = new BufferedStream(stream, _trunkSize))
|
|
{
|
|
IntPtr ptr = buffer.AddrOfPinnedObject();
|
|
foreach (T s in samples)
|
|
{
|
|
buffer.Array[index++] = s;
|
|
|
|
if (index == buffer.Array.Length)
|
|
{
|
|
int writeCount = index * _elementSize;
|
|
Marshal.Copy(ptr, byteBuffer, 0, writeCount);
|
|
bufferStream.Write(byteBuffer, 0, writeCount);
|
|
index = 0;
|
|
}
|
|
}
|
|
if (index != 0)
|
|
{
|
|
int writeCount = index * _elementSize;
|
|
Marshal.Copy(ptr, byteBuffer, 0, writeCount);
|
|
bufferStream.Write(byteBuffer, 0, writeCount);
|
|
index = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a copy of the first element in the storage. If the storage is empty, a default value will be returned
|
|
/// </summary>
|
|
/// <returns>A copy of the first element in the storage. If the storage is empty, a default value will be returned</returns>
|
|
public T Peek()
|
|
{
|
|
using (FileStream stream = _fileInfo.OpenRead())
|
|
using (PinnedArray<Byte> buffer = new PinnedArray<byte>(_elementSize))
|
|
{
|
|
return (stream.Read(buffer.Array, 0, _elementSize) > 0) ?
|
|
(T)Marshal.PtrToStructure(buffer.AddrOfPinnedObject(), typeof(T)) :
|
|
new T();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The file name of the storage
|
|
/// </summary>
|
|
public String FileName
|
|
{
|
|
get
|
|
{
|
|
return _fileInfo.FullName;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Estimate the number of elements in this storage as the size of the storage divided by the size of the elements
|
|
/// </summary>
|
|
/// <returns>An estimation of the number of elements in this storage</returns>
|
|
public int EstimateSize()
|
|
{
|
|
return
|
|
_fileInfo.Exists ?
|
|
(int)(_fileInfo.Length / (_elementSize)) :
|
|
0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the subsampled data in this storage
|
|
/// </summary>
|
|
/// <param name="subsampleRate">The subsample rate</param>
|
|
/// <returns>The subsampled data in this storage</returns>
|
|
public IEnumerable<T> GetSubsamples(int subsampleRate)
|
|
{
|
|
if (!_fileInfo.Exists)
|
|
yield break;
|
|
|
|
int bufferSize = _elementSize * subsampleRate;
|
|
using (FileStream stream = _fileInfo.OpenRead())
|
|
using (BufferedStream bufferStream = new BufferedStream(stream, _trunkSize))
|
|
using (PinnedArray<Byte> buffer = new PinnedArray<byte>(bufferSize))
|
|
using (PinnedArray<T> structure = new PinnedArray<T>(subsampleRate))
|
|
{
|
|
IntPtr structAddr = structure.AddrOfPinnedObject();
|
|
IntPtr addr = buffer.AddrOfPinnedObject();
|
|
while (bufferStream.Read(buffer.Array, 0, bufferSize) > 0)
|
|
{
|
|
Toolbox.memcpy(structAddr, addr, bufferSize);
|
|
yield return structure.Array[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
#region IEnumerable<T> Members
|
|
/// <summary>
|
|
/// Get the data in this storage
|
|
/// </summary>
|
|
/// <returns>The data in this storage</returns>
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
if (!_fileInfo.Exists)
|
|
yield break;
|
|
|
|
int elementsInTrunk = _trunkSize / _elementSize;
|
|
if (elementsInTrunk <= 0)
|
|
elementsInTrunk = 1;
|
|
|
|
Byte[] buffer = new byte[_elementSize * elementsInTrunk];
|
|
|
|
using (FileStream stream = _fileInfo.OpenRead())
|
|
using (BufferedStream bufferStream = new BufferedStream(stream, _trunkSize))
|
|
using (PinnedArray<T> structures = new PinnedArray<T>(elementsInTrunk))
|
|
{
|
|
IntPtr structAddr = structures.AddrOfPinnedObject();
|
|
int bytesRead;
|
|
while ((bytesRead = bufferStream.Read(buffer, 0, buffer.Length)) > 0)
|
|
{
|
|
Marshal.Copy(buffer, 0, structAddr, bytesRead);
|
|
int elementsRead = bytesRead / _elementSize;
|
|
for (int i = 0; i < elementsRead; i++)
|
|
{
|
|
yield return structures.Array[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable Members
|
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return GetEnumerator();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|