From 0681fefff0080f09a0ce2f694c421ca78be62929 Mon Sep 17 00:00:00 2001 From: "akpaev.e" Date: Mon, 14 Jul 2025 22:48:37 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/ObjectExtensions.cs | 22 ++++++ .../FileDatabaseConnection.cs | 30 +++----- OneSTools.FileDatabase/HighLevel/Table.cs | 29 ++++---- OneSTools.FileDatabase/HighLevel/TableRow.cs | 27 +++++++ OneSTools.FileDatabase/HighLevel/TableRows.cs | 74 +++++++++---------- OneSTools.FileDatabase/HighLevel/Tables.cs | 11 +++ .../OneSTools.FileDatabase.csproj | 11 +-- .../OneSTools.FileDatabaseTestApp.csproj | 3 +- OneSTools.FileDatabaseTestApp/Program.cs | 7 +- 9 files changed, 130 insertions(+), 84 deletions(-) create mode 100644 OneSTools.FileDatabase/Extensions/ObjectExtensions.cs create mode 100644 OneSTools.FileDatabase/HighLevel/TableRow.cs create mode 100644 OneSTools.FileDatabase/HighLevel/Tables.cs diff --git a/OneSTools.FileDatabase/Extensions/ObjectExtensions.cs b/OneSTools.FileDatabase/Extensions/ObjectExtensions.cs new file mode 100644 index 0000000..1a6b06b --- /dev/null +++ b/OneSTools.FileDatabase/Extensions/ObjectExtensions.cs @@ -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"); + } +} \ No newline at end of file diff --git a/OneSTools.FileDatabase/FileDatabaseConnection.cs b/OneSTools.FileDatabase/FileDatabaseConnection.cs index 6187708..731dabe 100644 --- a/OneSTools.FileDatabase/FileDatabaseConnection.cs +++ b/OneSTools.FileDatabase/FileDatabaseConnection.cs @@ -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 { /// /// Provides properties and methods for reading 1C file database data /// - 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 /// /// The flag of database opening /// - public bool Opened { get; private set; } = false; + public bool Opened { get; private set; } /// /// Version of the database file /// @@ -40,20 +35,19 @@ namespace OneSTools.FileDatabase /// /// A collection of database tables /// - public ReadOnlyCollection Tables { get; private set; } = null; - - public FileDatabaseConnection(string path) - => _path = path; + public Tables Tables { get; private set; } + + public Table this[string tableName] => Tables[tableName]; /// - /// Open database file + /// Open a database file /// 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
(); - 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()); } /// - /// Close database file + /// Close the database file /// public void Close() { diff --git a/OneSTools.FileDatabase/HighLevel/Table.cs b/OneSTools.FileDatabase/HighLevel/Table.cs index 0156f11..5cbfe4e 100644 --- a/OneSTools.FileDatabase/HighLevel/Table.cs +++ b/OneSTools.FileDatabase/HighLevel/Table.cs @@ -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 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 /// /// Internal name of the table /// - public string Name { get; private set; } + public string Name { get; } /// /// Collection of table fields /// - public ReadOnlyCollection Fields { get; private set; } = null; + public Field[] Fields { get; private set; } /// /// Collection of table indexes /// - public ReadOnlyCollection Indexes { get; private set; } = null; - public bool RecordLock { get; private set; } + public Index[] Indexes { get; private set; } + public bool RecordLock { get; } /// /// Collection of table rows /// - public IReadOnlyList Rows { get; private set; } = null; + public IReadOnlyList 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(); - 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(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; } } diff --git a/OneSTools.FileDatabase/HighLevel/TableRow.cs b/OneSTools.FileDatabase/HighLevel/TableRow.cs new file mode 100644 index 0000000..3bf2cb6 --- /dev/null +++ b/OneSTools.FileDatabase/HighLevel/TableRow.cs @@ -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"); + } + } +} \ No newline at end of file diff --git a/OneSTools.FileDatabase/HighLevel/TableRows.cs b/OneSTools.FileDatabase/HighLevel/TableRows.cs index 2872010..4a904ed 100644 --- a/OneSTools.FileDatabase/HighLevel/TableRows.cs +++ b/OneSTools.FileDatabase/HighLevel/TableRows.cs @@ -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 + internal class TableRows : IReadOnlyList { 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 GetEnumerator() + public IEnumerator 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; diff --git a/OneSTools.FileDatabase/HighLevel/Tables.cs b/OneSTools.FileDatabase/HighLevel/Tables.cs new file mode 100644 index 0000000..d2eb4bb --- /dev/null +++ b/OneSTools.FileDatabase/HighLevel/Tables.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace OneSTools.FileDatabase.HighLevel; + +public class Tables(IList
list) : ReadOnlyCollection
(list) +{ + public Table this[string name] + => this.FirstOrDefault(c => c.Name == name); +} \ No newline at end of file diff --git a/OneSTools.FileDatabase/OneSTools.FileDatabase.csproj b/OneSTools.FileDatabase/OneSTools.FileDatabase.csproj index b16fc40..bcbfb51 100644 --- a/OneSTools.FileDatabase/OneSTools.FileDatabase.csproj +++ b/OneSTools.FileDatabase/OneSTools.FileDatabase.csproj @@ -1,18 +1,19 @@  - netstandard2.1 + net9.0 OneSTools.FileDatabase OneSTools.FileDatabase Akpaev Evgeny Akpaev Evgeny Библиотека для чтения данных файловых информационных баз 1С Akpaev Evgeny - onestools_icon_nuget.png true https://github.com/akpaevj/OneSTools.FileDatabase https://github.com/akpaevj/OneSTools.FileDatabase LICENSE + default + 1.0.1 @@ -21,13 +22,9 @@ - - True - - True - + diff --git a/OneSTools.FileDatabaseTestApp/OneSTools.FileDatabaseTestApp.csproj b/OneSTools.FileDatabaseTestApp/OneSTools.FileDatabaseTestApp.csproj index 59ad671..986fd59 100644 --- a/OneSTools.FileDatabaseTestApp/OneSTools.FileDatabaseTestApp.csproj +++ b/OneSTools.FileDatabaseTestApp/OneSTools.FileDatabaseTestApp.csproj @@ -2,9 +2,10 @@ Exe - netcoreapp3.1 + net9.0 OneSTools.FileDatabaseTestApp OneSTools.FileDatabaseTestApp + default diff --git a/OneSTools.FileDatabaseTestApp/Program.cs b/OneSTools.FileDatabaseTestApp/Program.cs index 5852838..e6a1b11 100644 --- a/OneSTools.FileDatabaseTestApp/Program.cs +++ b/OneSTools.FileDatabaseTestApp/Program.cs @@ -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:");