1
0
mirror of https://github.com/akpaevj/OneSTools.FileDatabase.git synced 2026-04-24 19:13:53 +02:00

Улучшение UX

This commit is contained in:
akpaev.e
2025-07-14 22:48:37 +03:00
parent 6f4c1c6294
commit 0681fefff0
9 changed files with 130 additions and 84 deletions
@@ -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()
{
+16 -13
View File
@@ -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");
}
}
}
+33 -41
View File
@@ -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>
+3 -4
View File
@@ -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:");