Skip to content

Instantly share code, notes, and snippets.

@jirkapenzes
Created May 4, 2013 22:09
Show Gist options
  • Save jirkapenzes/5518928 to your computer and use it in GitHub Desktop.
Save jirkapenzes/5518928 to your computer and use it in GitHub Desktop.
FileIndex - RTree - přímý přístup do souboru
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace GraphAnalyzer.RTree.FileIndex
{
public class BaseFile<T>
{
private IList<IRTreeEdge<T>> _buffer;
private int _currentBufferAddress;
private readonly IExtendedFileManager<T> _fileManager;
private readonly int _treeOrder = RTreeConfig.Instance.TreeOrder; // řád stromu
private readonly int _capacity;
public BaseFile(IExtendedFileManager<T> fileManager, int capacity)
{
_buffer = new List<IRTreeEdge<T>>();
_fileManager = fileManager;
_currentBufferAddress = -1;
_capacity = capacity;
}
public void SaveEdge(Stream stream, IRTreeEdge<T> edge, int address)
{
// prostě uložím jednu položku do souboru
_fileManager.Save(stream, edge, address);
}
public IRTreeEdge<T> LoadEdge(Stream stream, int address)
{
// komentáře jsou ke třetímu řádu (předpokládám tři potomky)
// zjistím adresu bloku (př. pokud chci 7 prvek, tak patří do druhého bloku [7 / 3 = 2,333])
int bufferAddress = address / _treeOrder;
// vypočítám adresu prvku v jednom bloku
// soubor vypadá nějak takto: | 0 1 2 | 3 4 5 | 6 7 8 | 9 10 11 | ...
// já načetl druhý blok -> | 6 7 8 | -> a chci získat adresu sedmičky -> tj. 1
// 7 - (2 * 3) = 1
int dataAddressInBlock = address - (bufferAddress * _treeOrder);
// ověřím, jestli už náhodou není blok načtený
if (bufferAddress == _currentBufferAddress)
{
return _buffer[dataAddressInBlock];
}
// pokud chci adresu z jiného bloku, tak musím načíst nový blok do bufferu
LoadBuffer(stream, bufferAddress * _treeOrder);
return _buffer[dataAddressInBlock];
}
private void LoadBuffer(Stream stream, int address)
{
int count = _treeOrder;
// zjistím, zda mohu načíst maximální počet prvků (konec souboru)
if (IsLastBlock(address))
{
// pokud jsem na konci, tak si vypočítám, kolik je v posledním bloku dat
// nemusí být celý obsazen. Př. Chci načíst poslední blok, ale nikolic 3 prvky, ale 2
// 0 1 2 | 3 4 5 | 6 7
// count = 8 - (2 * 3) = 2
count = _capacity - (address * _treeOrder);
}
// načtu nový buffer
_buffer = _fileManager.LoadEdge(stream, address, count);
// nastaví novou adresu aktuálního bloku dat
_currentBufferAddress = address;
}
private bool IsLastBlock(int address)
{
int lastBlock = _capacity / _treeOrder;
return lastBlock == address;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GraphAnalyzer.RTree.FileIndex
{
internal class Converter
{
public static byte[] ConvertStringToByteArray(string text, int capacity)
{
var byteText = text.Length < 10 ? text.PadRight(10, ' ') : text.Substring(0, 10);
return Encoding.ASCII.GetBytes(byteText);
}
public static string ConvertByteArrayToString(byte[] bytes)
{
var text = "";
foreach (var c in Encoding.ASCII.GetChars(bytes))
text = text + c;
return text.Trim();
}
public static byte[] ConvertIntToByteArray(int i)
{
return BitConverter.GetBytes(i);
}
public static int ConvertByteArrayToInt(byte[] bytes)
{
return BitConverter.ToInt32(bytes, 0);
}
public static byte[] ConvertDoubleToByteArray(double d)
{
return BitConverter.GetBytes(d);
}
public static double ConvertByteArrayToDouble(byte[] bytes)
{
return BitConverter.ToDouble(bytes, 0);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GraphAnalyzer.RTree.FileIndex
{
public class FileDataBlock<T>
{
public int Address { get; set; }
public T Data { get; set; }
}
}
using System.Collections.Generic;
using System.IO;
namespace GraphAnalyzer.RTree.FileIndex
{
public class FileManager<T>
{
private readonly int _treeOrder;
public FileManager(int treeOrder)
{
_treeOrder = treeOrder;
}
public FileNode MakeFileNode(RTreeNode<T> rTreeNode, int blockAddress, ref int currentBlockAddress)
{
var fileNode = new FileNode
{
Position = blockAddress,
BaseBlockAddress = -1,
RTreeArea = new RTreeArea
{
X = rTreeNode.RTreeArea.X,
Y = rTreeNode.RTreeArea.Y,
Width = rTreeNode.RTreeArea.Width,
Height = rTreeNode.RTreeArea.Height
},
ChildrenAddresses = new List<int>(_treeOrder)
};
if (rTreeNode.RTreeEdge != null)
{
for (var i = 0; i < _treeOrder; i++)
fileNode.ChildrenAddresses.Add(-1);
}
else
{
for (var i = 0; i < _treeOrder; i++)
{
if (i < rTreeNode.Children.Count)
fileNode.ChildrenAddresses.Add(++currentBlockAddress);
else
fileNode.ChildrenAddresses.Add(-1);
}
}
return fileNode;
}
public void SaveFileNode(Stream stream, FileNode node, int fileAddress)
{
stream.Seek(fileAddress * GetFileNodeSize(), SeekOrigin.Begin);
var writer = new BinaryWriter(stream);
writer.Write(Converter.ConvertIntToByteArray(node.Position));
writer.Write(Converter.ConvertIntToByteArray(node.BaseBlockAddress));
writer.Write(Converter.ConvertDoubleToByteArray(node.RTreeArea.X));
writer.Write(Converter.ConvertDoubleToByteArray(node.RTreeArea.Y));
writer.Write(Converter.ConvertDoubleToByteArray(node.RTreeArea.Width));
writer.Write(Converter.ConvertDoubleToByteArray(node.RTreeArea.Height));
foreach (var childrenAddress in node.ChildrenAddresses)
writer.Write(Converter.ConvertIntToByteArray(childrenAddress));
}
public FileNode LoadNode(Stream stream, int blockAddress)
{
var fileNode = new FileNode();
stream.Seek(blockAddress * GetFileNodeSize(), SeekOrigin.Begin);
fileNode.Position = LoadValueInteger(stream);
fileNode.BaseBlockAddress = LoadValueInteger(stream);
fileNode.RTreeArea = new RTreeArea
{
X = LoadValueDouble(stream),
Y = LoadValueDouble(stream),
Width = LoadValueDouble(stream),
Height = LoadValueDouble(stream)
};
for (var i = 0; i < _treeOrder; i++)
{
var address = LoadValueInteger(stream);
if (address > 0)
fileNode.ChildrenAddresses.Add(address);
}
return fileNode;
}
private static int LoadValueInteger(Stream stream)
{
var bytes = new byte[4];
stream.Read(bytes, 0, sizeof(int));
return Converter.ConvertByteArrayToInt(bytes);
}
private static double LoadValueDouble(Stream stream)
{
var bytes = new byte[8];
stream.Read(bytes, 0, sizeof(double));
return Converter.ConvertByteArrayToDouble(bytes);
}
public int GetFileNodeSize()
{
var size = sizeof(int); // position
size += sizeof(int); // BaseBlockAddress
size += sizeof(double); // RTreeArea.X
size += sizeof(double); // RTreeArea.Y
size += sizeof(double); // RTreeArea.Width
size += sizeof(double); // RTreeArea.Height
for (var i = 0; i < _treeOrder; i++) // Children address
size += sizeof(int);
return size;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GraphAnalyzer.RTree.FileIndex
{
public class FileNode
{
public FileNode()
{
ChildrenAddresses = new List<int>();
}
public int Position { get; set; }
public int BaseBlockAddress { get; set; }
public RTreeArea RTreeArea { get; set; }
public IList<int> ChildrenAddresses { get; set; }
public bool HasChildren()
{
return ChildrenAddresses.Any(address => address > 0);
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace GraphAnalyzer.RTree.FileIndex
{
public interface IExtendedFileManager<T>
{
// umí uložit soubor na požadovanou pozici do streamu
void Save(Stream stream, IRTreeEdge<T> rTreeEdge, int address);
// umít načíst data ze soubory (i větší počet najednou)
IList<IRTreeEdge<T>> LoadEdge(Stream stream, int address, int count);
// umí vypočítat adresu jednoho bloku dat
int GetFileSize();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment