You've already forked OneSTools.FileDatabase
mirror of
https://github.com/akpaevj/OneSTools.FileDatabase.git
synced 2026-04-24 19:13:53 +02:00
Улучшение UX
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace OneSTools.FileDatabase.Extensions;
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static Guid AsGuid(this object obj)
|
||||
{
|
||||
if (obj is byte[] { Length: 16 } bytes)
|
||||
return new Guid(bytes);
|
||||
|
||||
throw new Exception("failed to convert object to GUID");
|
||||
}
|
||||
|
||||
public static string AsString(this object obj)
|
||||
{
|
||||
if (obj is string value)
|
||||
return value;
|
||||
|
||||
throw new Exception("failed to convert object to string");
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,18 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using OneSTools.FileDatabase.LowLevel;
|
||||
using System.Linq;
|
||||
using OneSTools.FileDatabase.LowLevel.Pages;
|
||||
using OneSTools.FileDatabase.LowLevel.Files;
|
||||
using OneSTools.BracketsFile;
|
||||
using System.Text;
|
||||
using System.Data.Common;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
|
||||
namespace OneSTools.FileDatabase
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides properties and methods for reading 1C file database data
|
||||
/// </summary>
|
||||
public class FileDatabaseConnection : IDisposable
|
||||
public class FileDatabaseConnection(string path) : IDisposable
|
||||
{
|
||||
private readonly string _path;
|
||||
private FileDatabaseStream _stream;
|
||||
private HeaderPage _headerPage;
|
||||
private FreePagesPage _freePagesPage;
|
||||
@@ -28,7 +23,7 @@ namespace OneSTools.FileDatabase
|
||||
/// <summary>
|
||||
/// The flag of database opening
|
||||
/// </summary>
|
||||
public bool Opened { get; private set; } = false;
|
||||
public bool Opened { get; private set; }
|
||||
/// <summary>
|
||||
/// Version of the database file
|
||||
/// </summary>
|
||||
@@ -40,20 +35,19 @@ namespace OneSTools.FileDatabase
|
||||
/// <summary>
|
||||
/// A collection of database tables
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Table> Tables { get; private set; } = null;
|
||||
|
||||
public FileDatabaseConnection(string path)
|
||||
=> _path = path;
|
||||
public Tables Tables { get; private set; }
|
||||
|
||||
public Table this[string tableName] => Tables[tableName];
|
||||
|
||||
/// <summary>
|
||||
/// Open database file
|
||||
/// Open a database file
|
||||
/// </summary>
|
||||
public void Open()
|
||||
{
|
||||
if (!File.Exists(_path))
|
||||
throw new FileNotFoundException("Cannot find a database file", _path);
|
||||
if (!File.Exists(path))
|
||||
throw new FileNotFoundException("Cannot find a database file", path);
|
||||
|
||||
var stream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
_stream = new FileDatabaseStream(stream);
|
||||
|
||||
ReadStructure();
|
||||
@@ -76,7 +70,7 @@ namespace OneSTools.FileDatabase
|
||||
|
||||
var tables = new List<Table>();
|
||||
|
||||
for (int i = 0; i < _databaseDescriptionFile.TablesCount; i++)
|
||||
for (var i = 0; i < _databaseDescriptionFile.TablesCount; i++)
|
||||
{
|
||||
var tableDefinitionData = _databaseDescriptionFile.ReadTableDefinitionData();
|
||||
var tableDefinitionStr = Encoding.UTF8.GetString(tableDefinitionData);
|
||||
@@ -86,11 +80,11 @@ namespace OneSTools.FileDatabase
|
||||
tables.Add(table);
|
||||
}
|
||||
|
||||
Tables = tables.AsReadOnly();
|
||||
Tables = new Tables(tables.AsReadOnly());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close database file
|
||||
/// Close the database file
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using OneSTools.FileDatabase.LowLevel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace OneSTools.FileDatabase.HighLevel
|
||||
{
|
||||
public class Table
|
||||
{
|
||||
internal Dictionary<string, int> FieldNameNumberCache { get; private set; } = new();
|
||||
|
||||
internal int MaxRowSize { get; private set; }
|
||||
internal uint DataFilePage { get; private set; }
|
||||
internal uint UnlimitedLengthDataFilePage { get; private set; }
|
||||
@@ -17,26 +21,26 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
/// <summary>
|
||||
/// Internal name of the table
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
public string Name { get; }
|
||||
/// <summary>
|
||||
/// Collection of table fields
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Field> Fields { get; private set; } = null;
|
||||
public Field[] Fields { get; private set; }
|
||||
/// <summary>
|
||||
/// Collection of table indexes
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<Index> Indexes { get; private set; } = null;
|
||||
public bool RecordLock { get; private set; }
|
||||
public Index[] Indexes { get; private set; }
|
||||
public bool RecordLock { get; }
|
||||
/// <summary>
|
||||
/// Collection of table rows
|
||||
/// </summary>
|
||||
public IReadOnlyList<object[]> Rows { get; private set; } = null;
|
||||
public IReadOnlyList<TableRow> Rows { get; private set; }
|
||||
|
||||
internal Table(FileDatabaseStream stream, BracketsNode node)
|
||||
{
|
||||
Name = node[0];
|
||||
|
||||
for (int i = 2; i < node.Count; i++)
|
||||
for (var i = 2; i < node.Count; i++)
|
||||
{
|
||||
var currentNode = node[i];
|
||||
string nodeName = currentNode[0];
|
||||
@@ -69,7 +73,7 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
{
|
||||
var fields = new List<Field>();
|
||||
|
||||
for (int i = 1; i < node.Count; i++)
|
||||
for (var i = 1; i < node.Count; i++)
|
||||
{
|
||||
var field = new Field();
|
||||
field.Read(node[i]);
|
||||
@@ -91,7 +95,8 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
if (fields.Count > 0 && fields[0].Type == FieldType.RowVersion && RecordLock)
|
||||
MaxRowSize += 8;
|
||||
|
||||
Fields = fields.AsReadOnly();
|
||||
Fields = fields.ToArray();
|
||||
FieldNameNumberCache = Fields.Select((e, i) => new KeyValuePair<string, int>(e.Name, i)).ToDictionary(e => e.Key, e => e.Value);
|
||||
}
|
||||
|
||||
private void ReadIndexes(BracketsNode node)
|
||||
@@ -100,7 +105,7 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
|
||||
if (node.Count > 1)
|
||||
{
|
||||
for (int i = 1; i < node.Count; i++)
|
||||
for (var i = 1; i < node.Count; i++)
|
||||
{
|
||||
var index = new Index();
|
||||
index.Read(node[i]);
|
||||
@@ -109,12 +114,10 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
}
|
||||
}
|
||||
|
||||
Indexes = indexes.AsReadOnly();
|
||||
Indexes = indexes.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
=> Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace OneSTools.FileDatabase.HighLevel;
|
||||
|
||||
public class TableRow
|
||||
{
|
||||
private readonly Table _table;
|
||||
|
||||
public object[] Values { get; }
|
||||
|
||||
internal TableRow(Table table, object[] values)
|
||||
{
|
||||
_table = table;
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public object this[string name]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_table.FieldNameNumberCache.TryGetValue(name, out var index))
|
||||
return Values[index];
|
||||
|
||||
throw new Exception("failed to get field index");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,11 @@ using OneSTools.FileDatabase.LowLevel;
|
||||
using OneSTools.FileDatabase.LowLevel.Files;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace OneSTools.FileDatabase.HighLevel
|
||||
{
|
||||
internal class TableRows : IReadOnlyList<object[]>
|
||||
internal class TableRows : IReadOnlyList<TableRow>
|
||||
{
|
||||
private readonly FileDatabaseStream _stream;
|
||||
private readonly Table _table;
|
||||
@@ -23,7 +22,7 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
_table = table;
|
||||
}
|
||||
|
||||
public object[] this[int index]
|
||||
public TableRow this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -46,9 +45,9 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<object[]> GetEnumerator()
|
||||
public IEnumerator<TableRow> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return Get(i + 1);
|
||||
}
|
||||
@@ -65,7 +64,7 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
{
|
||||
if (_table.DataFilePage != 0)
|
||||
{
|
||||
_dataFile = new DataFile(_stream, _table.DataFilePage, _table.MaxRowSize, _table.Fields.Count > 0 && _table.Fields[0].Type != FieldType.RowVersion && _table.RecordLock);
|
||||
_dataFile = new DataFile(_stream, _table.DataFilePage, _table.MaxRowSize, _table.Fields.Length > 0 && _table.Fields[0].Type != FieldType.RowVersion && _table.RecordLock);
|
||||
|
||||
if (_dataFile.HasData())
|
||||
{
|
||||
@@ -84,47 +83,45 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
}
|
||||
}
|
||||
|
||||
private object[] Get(int rowNumber)
|
||||
private TableRow Get(int rowNumber)
|
||||
{
|
||||
InitializeFiles();
|
||||
|
||||
_dataFile.GoToRow(rowNumber);
|
||||
|
||||
var values = new object[_table.Fields.Count];
|
||||
var values = new object[_table.Fields.Length];
|
||||
|
||||
var rawData = _dataFile.ReadRow();
|
||||
|
||||
if (rawData == null)
|
||||
return null;
|
||||
else
|
||||
|
||||
var currentOffset = 0;
|
||||
|
||||
for (var i = 0; i < _table.Fields.Length; i++)
|
||||
{
|
||||
var currentOffset = 0;
|
||||
var field = _table.Fields[i];
|
||||
|
||||
for (int i = 0; i < _table.Fields.Count; i++)
|
||||
var fieldData = rawData[currentOffset..(currentOffset + field.MaxSize)];
|
||||
|
||||
currentOffset += field.MaxSize;
|
||||
|
||||
values[i] = field.Type switch
|
||||
{
|
||||
var field = _table.Fields[i];
|
||||
|
||||
var fieldData = rawData[currentOffset..(currentOffset + field.MaxSize)];
|
||||
|
||||
currentOffset += field.MaxSize;
|
||||
|
||||
values[i] = field.Type switch
|
||||
{
|
||||
FieldType.Binary => ReadBinary(fieldData, field.Nullable),
|
||||
FieldType.Logical => ReadLogical(fieldData, field.Nullable),
|
||||
FieldType.Numeric => ReadNumericValue(fieldData, field.Precision, field.Nullable),
|
||||
FieldType.NChar => ReadNChar(fieldData, field.Nullable),
|
||||
FieldType.NVarChar => ReadNVarChar(fieldData, field.Nullable),
|
||||
FieldType.RowVersion => ReadRowVersion(fieldData, field.Nullable),
|
||||
FieldType.NText => ReadNText(fieldData, field.Nullable),
|
||||
FieldType.Image => ReadImage(fieldData, field.Nullable),
|
||||
FieldType.DateTime => ReadDateTime(fieldData, field.Nullable),
|
||||
_ => throw new Exception($"Reading value for a field with type {field.Type} is not implemented")
|
||||
};
|
||||
}
|
||||
|
||||
return values;
|
||||
FieldType.Binary => ReadBinary(fieldData, field.Nullable),
|
||||
FieldType.Logical => ReadLogical(fieldData, field.Nullable),
|
||||
FieldType.Numeric => ReadNumericValue(fieldData, field.Precision, field.Nullable),
|
||||
FieldType.NChar => ReadNChar(fieldData, field.Nullable),
|
||||
FieldType.NVarChar => ReadNVarChar(fieldData, field.Nullable),
|
||||
FieldType.RowVersion => ReadRowVersion(fieldData, field.Nullable),
|
||||
FieldType.NText => ReadNText(fieldData, field.Nullable),
|
||||
FieldType.Image => ReadImage(fieldData, field.Nullable),
|
||||
FieldType.DateTime => ReadDateTime(fieldData, field.Nullable),
|
||||
_ => throw new Exception($"Reading value for a field with type {field.Type} is not implemented")
|
||||
};
|
||||
}
|
||||
|
||||
return new TableRow(_table, values);
|
||||
}
|
||||
|
||||
private byte[] ReadBinary(byte[] data, bool nullable)
|
||||
@@ -323,15 +320,10 @@ namespace OneSTools.FileDatabase.HighLevel
|
||||
return true;
|
||||
}
|
||||
|
||||
private byte[] GetValueData(byte[] data, bool nullable)
|
||||
{
|
||||
if (nullable)
|
||||
return data[1..];
|
||||
else
|
||||
return data;
|
||||
}
|
||||
private static byte[] GetValueData(byte[] data, bool nullable)
|
||||
=> nullable ? data[1..] : data;
|
||||
|
||||
private int ReadTetrad(byte b, bool second = false)
|
||||
private static int ReadTetrad(byte b, bool second = false)
|
||||
{
|
||||
if (second)
|
||||
return b & 0b_0000_1111;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace OneSTools.FileDatabase.HighLevel;
|
||||
|
||||
public class Tables(IList<Table> list) : ReadOnlyCollection<Table>(list)
|
||||
{
|
||||
public Table this[string name]
|
||||
=> this.FirstOrDefault(c => c.Name == name);
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<AssemblyName>OneSTools.FileDatabase</AssemblyName>
|
||||
<RootNamespace>OneSTools.FileDatabase</RootNamespace>
|
||||
<Authors>Akpaev Evgeny</Authors>
|
||||
<Company>Akpaev Evgeny</Company>
|
||||
<Description>Библиотека для чтения данных файловых информационных баз 1С</Description>
|
||||
<Copyright>Akpaev Evgeny</Copyright>
|
||||
<PackageIcon>onestools_icon_nuget.png</PackageIcon>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageProjectUrl>https://github.com/akpaevj/OneSTools.FileDatabase</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/akpaevj/OneSTools.FileDatabase</RepositoryUrl>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<LangVersion>default</LangVersion>
|
||||
<Version>1.0.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -21,13 +22,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\onestools_icon_nuget.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
<PackagePath/>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<AssemblyName>OneSTools.FileDatabaseTestApp</AssemblyName>
|
||||
<RootNamespace>OneSTools.FileDatabaseTestApp</RootNamespace>
|
||||
<LangVersion>default</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -10,10 +10,9 @@ namespace OneSTools.FileDatabaseTestApp
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var filePath = @"C:\Users\akpaev.e.ENTERPRISE\Desktop\Новая папка (2)\1Cv8.1CD";
|
||||
var filePath2 = @"C:\Users\akpaev.e.ENTERPRISE\Documents\InfoBase10\1Cv8.1CD";
|
||||
var filePath = "/home/usr1cv8/crserver/test/1cv8ddb.1CD";
|
||||
|
||||
using var database = new FileDatabaseConnection(filePath2);
|
||||
using var database = new FileDatabaseConnection(filePath);
|
||||
database.Open();
|
||||
|
||||
foreach(var table in database.Tables)
|
||||
@@ -26,7 +25,7 @@ namespace OneSTools.FileDatabaseTestApp
|
||||
foreach (var field in table.Fields)
|
||||
Console.WriteLine($"\t\tField \"{field}\"");
|
||||
|
||||
if (table.Indexes.Count > 0)
|
||||
if (table.Indexes.Length > 0)
|
||||
{
|
||||
// list the table indexes
|
||||
Console.WriteLine("\tIndexes:");
|
||||
|
||||
Reference in New Issue
Block a user