PixSTD.DataUtilities
0.1.10
dotnet add package PixSTD.DataUtilities --version 0.1.10
NuGet\Install-Package PixSTD.DataUtilities -Version 0.1.10
<PackageReference Include="PixSTD.DataUtilities" Version="0.1.10" />
<PackageVersion Include="PixSTD.DataUtilities" Version="0.1.10" />
<PackageReference Include="PixSTD.DataUtilities" />
paket add PixSTD.DataUtilities --version 0.1.10
#r "nuget: PixSTD.DataUtilities, 0.1.10"
#:package PixSTD.DataUtilities@0.1.10
#addin nuget:?package=PixSTD.DataUtilities&version=0.1.10
#tool nuget:?package=PixSTD.DataUtilities&version=0.1.10
PixSTD.DataUtilities
Официальная библиотека от PixSTD
📦 NuGet: PixSTD.DataUtilities
👨💻 Автор: PixSTD
🐙 Исходный код: https://github.com/PixSTD/DataUtilities.dll
📄 Лицензия: MIT
PixSTD.DataUtilities — продвинутая библиотека для .NET, предоставляющая:
- 🔐 Безопасность — шифрование и защита данных
- 🗂️ Хранение — организация файлов с хешированием путей
- 📡 Сетевая подготовка — упаковка/распаковка данных для сетевой передачи
- 📦 Производительность — быстрая сериализация через MessagePack
- ⚡ Совместимость — .NET Standard 2.1, 8, 9, 10
- 🌐 Доступность — Windows, Linux, Android
- 📝 Наблюдаемость — полное логирование операций
📑 Оглавление
- 🚀 Быстрый старт
- 📖 Инициализация
- 💾 Сохранение и загрузка данных
- 📁 Копирование файлов и папок
- 📄 Перенос файлов и папок
- 🔍 Поиск файлов и папок
- 🗑️ Удаление файлов и папок
- 🛠️ Вспомогательные функции
- 🔐 Шифрование и работа с сетью
- 📝 Логирование и обработка событий
🚀 Быстрый старт
using DataUtilities;
using System;
using System.IO;
using System.Threading.Tasks;
// 1. Инициализация
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string appFolder = Path.Combine(localAppData, "CompanyName", "YourAppName");
var data = new PlayerData(
hash: "ваш_ключ_шифрования", // byte[] или string
startPath: appFolder, // куда сохранять файлы
lengthNameDirectory: HexLength.Short, // 8 символов для папки
lengthNameFile: HexLength.Short, // 8 символов для файла (Пример: "player/profile" → "a1b2c3d4/e5f67890")
offsetHashHex: -1 // Смещение начала хеша. Значение -1 означает автоматический сдвиг, равный длине хешируемого сегмента
);
// 2. Сохранение данных (асинхронно)
await data.SaveA(profile, "data/player/profile");
// → сохранит в зашифрованном виде с хешированными путями
// 3. Загрузка данных (асинхронно)
ProfileType profile; // ваш тип класса профиля
bool loaded = await data.LoadA<ProfileType>(out profile, "data/player/profile");
if (loaded)
Console.WriteLine("Профиль успешно загружен!");
else
Console.WriteLine("Профиль не найден или повреждён");
// 4. Отправка/получение по сети
byte[] networkData = data.EncryptNetworkData(request); // → готово к отправке
// На стороне получателя:
MemoryStream receivedStream = new MemoryStream(); // сюда приходят пакеты
// Когда получили кусок данных:
byte[] chunk = ...; // полученный кусок
receivedStream.Write(chunk, 0, chunk.Length);
// Обрабатываем всё, что накопилось
var remains = data.DecryptNetworkData<Request>(
receivedStream.ToArray(),
req =>
{
// Здесь ваша логика обработки запроса
Console.WriteLine($"Получен запрос: {req.Key}");
});
// remains — это неполный кусок, который ещё не образовал целое сообщение
receivedStream.SetLength(0); // очищаем поток
if (remains.Length > 0)
{
receivedStream.Write(remains.ToArray(), 0, remains.Length);
// теперь при следующем пакете остаток будет учтён
}
// 5. Логирование действий
data.Log += (logEvent) =>
{
if (logEvent.Level <= DataLogLevel.Info)
Console.WriteLine(logEvent.Message);
};
📖 Инициализация
🔧 Конструкторы
PlayerData(string hash, ...)
Создаёт экземпляр с строковым ключом шифрования.
// Простейший вариант
var storage = new PlayerData("мой-секретный-ключ");
// Полная настройка
var storage = new PlayerData(
hash: "мой-секретный-ключ",
startPath: "C:/MyApp/Data", // Куда сохранять файлы
lengthNameDirectory: HexLength.Medium, // Длина хеша для папок (16 символов)
lengthNameFile: HexLength.Short, // Длина хеша для файлов (8 символов)
offsetHashHex: -1 // Автосмещение для уникальности хешей
);
PlayerData(byte[] hash, ...)
То же самое, но с байтовым ключом (более безопасно).
// Генерация ключа из байтов
var keyBytes = Encoding.UTF8.GetBytes("мой-секретный-ключ");
var storage = new PlayerData(keyBytes);
⚙️ Методы настройки (можно вызывать после создания)
SetHash(string hash) / SetHash(byte[] hash)
Устанавливает или изменяет ключ шифрования.
var storage = new PlayerData("мой-временный-ключ");
// Позже меняем на постоянный (например, после ввода пароля пользователем)
storage.SetHash("мой-постоянный-ключ");
// Байтовый ключ (рекомендуется)
var secureHash = new byte[] { 0x01, 0x02, 0x03, ... };
storage.SetHash(secureHash);
⚠️ Важно: При смене ключа старые данные не смогут быть расшифрованы!
SetStartPath(string path)
Задаёт корневую папку для хранения данных.
// Для desktop-приложений
storage.SetStartPath(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"CompanyName",
"YourAppName"
));
// Для мобильных приложений (Xamarin/MAUI)
storage.SetStartPath(FileSystem.AppDataDirectory);
// Проверка: путь будет создан, если не существует
SetLengthNameDirectory(HexLength length)
SetLengthNameFile(HexLength length)
Настраивают длину хешированных имён.
// Возможные значения HexLength:
//Short - 8 символов (4 байта)
//Medium - 16 символов (8 байт)
//Long - 32 символа (16 байт)
//Full - 64 символа (32 байта) - по умолчанию
// Пример: компактные имена для мобильных устройств
storage.SetLengthNameDirectory(HexLength.Medium);
storage.SetLengthNameFile(HexLength.Medium);
// Путь "users/profile" → "a1b2e5f67890c3d4/e5f6a1b2c3d47890"
SetOffsetHashHex(int offsetHex)
Смещение в хеше для уменьшения коллизий.
// Фиксированное смещение
storage.SetOffsetHashHex(10); // Начинать хеш с 10-го символа
// Автоматическое смещение (рекомендуется)
storage.SetOffsetHashHex(-1); // Смещение = длина хешируемой строки
// Пример с offsetHashHex = -1:
// "users" (5 символов) → хеш начиная с 5-й позиции
// "profile" (7 символов) → хеш начиная с 7-й позиции
🎯 Примеры использования
Пример 1: Простое desktop-приложение
public class AppStorage
{
private readonly PlayerData storage;
public AppStorage()
{
storage = new PlayerData(
hash: "мой-секретный-ключ",
startPath: Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"PixSTD",
"MyApp"
),
lengthNameDirectory: HexLength.Medium,
lengthNameFile: HexLength.Medium,
offsetHashHex: -1
);
}
}
Пример 2: Поэтапная настройка
// Когда нужна гибкая настройка
var storage = new PlayerData("мой-секретный-ключ");
// Позже, после инициализации приложения
storage.SetHash("мой-секретный-ключ");
storage.SetStartPath(GetUserDataPath());
storage.SetLengthNameDirectory(HexLength.Medium);
storage.SetLengthNameFile(HexLength.Medium);
storage.SetOffsetHashHex(-1);
❗ Важные замечания
Ключ шифрования:
- Байтовый ключ: Минимум 16 байт
- Храните безопасно (не в коде!)
- При утере ключа данные не восстановить
Пути:
- Автоматически создаются недостающие папки
- Можно использовать относительные пути
Безопасность:
- Разные длины хешей для папок и файлов усложняют анализ структуры
- Смещение (
offsetHashHex) предотвращает pattern analysis
💾 Сохранение и загрузка данных
📤 Сохранение объектов
Save(object data, string encryptedPath, string unencryptedPath = "")
Синхронное сохранение данных.
SaveA(object data, string encryptedPath, string unencryptedPath = "")
Асинхронное сохранение (рекомендуется).
// Любой объект можно сохранить
var user = new { Name = "Иван", Age = 25, Email = "ivan@mail.com" };
var settings = new AppSettings { Theme = "Dark", Language = "RU" };
// Сохраняем в зашифрованном виде
storage.Save(user, "users/ivan/profile");
await storage.SaveA(settings, "app/settings");
// С сохранением в конкретную папку
await storage.SaveA(
data: user,
encryptedPath: "profile", // хешируется: "profile" → "e5f6a1b2c3d47890"
unencryptedPath: "C:/backups/users" // Не хешируется, используется как есть
);
📥 Загрузка объектов
Load<T>(Action<T> apply, string encryptedPath, string unencryptedPath = "")
Синхронная загрузка с обработкой через callback.
LoadA<T>(Action<T> apply, string encryptedPath, string unencryptedPath = "")
Асинхронная загрузка.
Load<T>(out T value, string encryptedPath, string unencryptedPath = "")
Загрузка с возвратом значения.
// Способ 1: Через callback (рекомендуется для сложной логики)
storage.Load<AppSettings>(settings =>
{
Console.WriteLine($"Тема: {settings.Theme}");
ApplyTheme(settings.Theme);
}, "app/settings");
// Асинхронный вариант
await storage.LoadA<List<Document>>(documents =>
{
foreach (var doc in documents)
ProcessDocument(doc);
}, "projects/report/documents");
// Способ 2: Получение значения напрямую
if (storage.Load<User>(out var user, "users/ivan/profile"))
{
Console.WriteLine($"Привет, {user.Name}!");
}
else
{
Console.WriteLine("Пользователь не найден");
}
// Загрузка с указанием папки
storage.Load<BackupData>(
data => RestoreBackup(data),
encryptedPath: "backup",
unencryptedPath: "D:/archives"
);
🔄 Работа с разными типами данных
// Примитивные типы
await storage.SaveA(42, "config/max_items");
await storage.SaveA("Hello World", "messages/greeting");
// Коллекции
var scores = new Dictionary<string, int>
{
["Иван"] = 100,
["Мария"] = 95
};
await storage.SaveA(scores, "game/scores");
// Сложные объекты
[MessagePackObject] // Использование атрибутов MessagePack уменьшает размер данных на 20-30%
public class Invoice
{
[Key(0)]
public string Number { get; set; }
[Key(1)]
public DateTime Date { get; set; }
[Key(2)]
public List<InvoiceItem> Items { get; set; }
[Key(3)]
public decimal Total { get; set; }
}
var invoice = new Invoice { /* ... */ };
await storage.SaveA(invoice, $"invoices/{invoice.Number}");
🎯 Пример использования
public class UserService
{
private readonly PlayerData storage;
public async Task<User> GetUserAsync(string userId)
{
if (storage.Load<User>(out var user, $"users/{userId}/profile"))
return user;
// Если пользователя нет - создаём нового
var newUser = new User { Id = userId, Created = DateTime.Now };
await storage.SaveA(newUser, $"users/{userId}/profile");
return newUser;
}
public async Task SaveUserSettingsAsync(string userId, UserSettings settings)
{
await storage.SaveA(settings, $"users/{userId}/settings");
}
public async Task<List<User>> GetAllUsersAsync()
{
var users = new List<User>();
// Загружаем всех пользователей из папки users/
var userFolders = storage.GetDirectories("users");
foreach (var folder in userFolders)
{
if (storage.Load<User>(out var user, "profile", folder))
users.Add(user);
}
return users;
}
}
📁 Копирование файлов и папок
📄 Копирование файлов
CopyFile(string fromEncryptedPath, string toEncryptedPath, ...)
Копирует один файл в другое место.
// Базовое копирование (перезаписывает существующий файл)
storage.CopyFile(
fromEncryptedPath: "users/ivan/profile",
toEncryptedPath: "backups/users/ivan_profile_backup"
);
// С указанием конкретных папок
storage.CopyFile(
fromEncryptedPath: "report",
toEncryptedPath: "archive/report_2026",
fromUnencryptedPath: "C:/reports/2026", // Исходная папка
toUnencryptedPath: "D:/archive", // Конечная папка
overwrite: true // Перезаписать если существует
);
// Безопасное копирование (не перезаписывает)
storage.CopyFile(
fromEncryptedPath: "config/settings",
toEncryptedPath: "config/settings_backup",
overwrite: false // Если файл уже существует - копирование не выполнится
);
📂 Копирование папок (рекурсивное)
CopyDirectory(string fromEncryptedPath, string toEncryptedPath, ...)
Копирует все файлы из одной папки в другую.
// Копирование всей папки
var (copied, total) = storage.CopyDirectory(
fromEncryptedPath: "users",
toEncryptedPath: "backups/2026/users"
);
Console.WriteLine($"Скопировано: {copied}/{total} файлов");
// Копирование с перезаписью
storage.CopyDirectory(
fromEncryptedPath: "app/logs",
toEncryptedPath: "archive/logs_january",
overwrite: true // Перезаписать существующие файлы
);
// Копирование между разными корневыми папками
storage.CopyDirectory(
fromEncryptedPath: "data/project_x",
toEncryptedPath: "backups/project_x",
fromUnencryptedPath: "C:/projects/current",
toUnencryptedPath: "D:/backups/archive"
);
🎯 Пример использования
public class BackupService
{
private readonly PlayerData storage;
public void CreateUserBackup(string userId, string backupName)
{
var backupPath = $"backups/{DateTime.Now:yyyy-MM-dd}/{userId}";
// Копируем все данные пользователя в бэкап
storage.CopyDirectory(
fromEncryptedPath: $"users/{userId}",
toEncryptedPath: $"{backupPath}"
);
// Копируем отдельно важные файлы с метаданными
var importantFiles = new[]
{
$"users/{userId}/profile",
$"users/{userId}/settings",
$"users/{userId}/subscription"
};
foreach (var file in importantFiles)
{
var fileName = PlayerData.GetNameFile(file);
storage.CopyFile(
fromEncryptedPath: file,
toEncryptedPath: $"{backupPath}/critical/{fileName}"
);
}
}
public void RestoreUserBackup(string userId, string backupDate)
{
// Восстанавливаем из бэкапа
storage.CopyDirectory(
fromEncryptedPath: $"backups/{backupDate}/{userId}",
toEncryptedPath: $"users/{userId}",
overwrite: true // Перезаписываем текущие данные
);
}
}
📄 Перенос файлов и папок
MoveFile(string fromEncryptedPath, string toEncryptedPath, ...)
Перемещает один файл в новое место.
Поддерживает перезапись (overwrite = true по умолчанию).
Возвращает:
true — файл успешно перемещён
false — не удалось (путь не найден, уже существует без overwrite, конфликт и т.д.)
// Простое перемещение с перезаписью
storage.MoveFile(
fromEncryptedPath: "users/ivan/profile",
toEncryptedPath: "users/ivan/profile_old"
);
// Без перезаписи (если файл существует — вернёт false)
storage.MoveFile(
fromEncryptedPath: "config/settings",
toEncryptedPath: "config/settings_backup",
overwrite: false
);
// Между разными корневыми папками
storage.MoveFile(
fromEncryptedPath: "report.pdf",
toEncryptedPath: "report_2026.pdf",
fromUnencryptedPath: "C:/reports",
toUnencryptedPath: "D:/archive",
overwrite: true
);
MoveDirectory(string fromEncryptedPath, string toEncryptedPath, ...)
Перемещает папку со всем содержимым (рекурсивно).
Поддерживает перезапись (overwrite = true по умолчанию).
Важно о перемещении:
- Если цель уже существует и
overwrite = false— метод вернётfalseи ничего не сделает. - При
overwrite = trueсуществующий файл/папка будет удалён перед перемещением (черезDeleteFile/DeleteDirectory).
Возвращает:
true — папка успешно перемещена
false — не удалось (путь не найден, уже существует без overwrite, нет прав и т.д.)
// Перемещение всей папки
storage.MoveDirectory(
fromEncryptedPath: "users/ivan",
toEncryptedPath: "archive/users/ivan_2026"
);
// Без перезаписи
storage.MoveDirectory(
fromEncryptedPath: "app/logs",
toEncryptedPath: "archive/logs_january",
overwrite: false
);
// Между разными дисками
storage.MoveDirectory(
fromEncryptedPath: "project_x/data",
toEncryptedPath: "backup/project_x_data",
fromUnencryptedPath: "C:/projects",
toUnencryptedPath: "D:/backups",
overwrite: true
);
🔍 Поиск файлов и папок
SearchFile(string encryptedPath, ...) / SearchDirectory(...)
Проверяет существование файла или папки.
// Проверка существования файла
if (storage.SearchFile("users/ivan/profile"))
{
Console.WriteLine("Профиль пользователя существует");
}
// Проверка существования папки
if (storage.SearchDirectory("users"))
{
var userCount = storage.QuantityDirectories("users");
Console.WriteLine($"Найдено пользователей: {userCount}");
}
// Поиск с указанием конкретной папки
var exists = storage.SearchFile(
encryptedPath: "report",
unencryptedPath: "C:/documents/reports"
);
GetFiles(string encryptedPath, ...) / GetDirectories(...)
Получает список файлов или папок.
// Получить все файлы в папке
var allFiles = storage.GetFiles("users/ivan");
foreach (var file in allFiles)
{
Console.WriteLine($"Файл: {file}");
}
// Получить все подпапки
var userFolders = storage.GetDirectories("users");
foreach (var folder in userFolders)
{
var userName = PlayerData.GetNameDirectory(folder);
Console.WriteLine($"Папка пользователя: {userName}");
}
// Получить только определённые файлы
var imageFiles = storage.GetFiles("gallery")
.Where(f => f.EndsWith(".jpg") || f.EndsWith(".png"));
QuantityFiles(...) / QuantityDirectories(...)
Подсчитывает количество файлов или папок.
// Подсчёт файлов в проекте
var fileCount = storage.QuantityFiles("projects/report");
var folderCount = storage.QuantityDirectories("projects");
Console.WriteLine($"Проект содержит: {fileCount} файлов в {folderCount} папках");
// Мониторинг использования хранилища
public StorageInfo GetStorageInfo()
{
return new StorageInfo
{
TotalFiles = storage.QuantityFiles(""),
TotalDirectories = storage.QuantityDirectories(""),
UserFiles = storage.QuantityFiles("users"),
BackupFiles = storage.QuantityFiles("backups")
};
}
🗑️ Удаление файлов и папок
DeleteFile(string encryptedPath, ...) / DeleteDirectory(...)
Удаляет файлы и папки (рекурсивно).
Возвращает:
true — файл/папка успешно удалены или уже не существовали
false — не удалось удалить (нет прав, файл заблокирован, путь некорректен и т.д.)
// Удаление одного файла
Console.WriteLine(storage.DeleteFile("temp/cache_data") ? "Файл удален" : "Не удалось удалить файл");
// Удаление папки со всем содержимым
Console.WriteLine(storage.DeleteDirectory("old_backups") ? "Папка удалена" : "Не удалось удалить папку");
// Очистка временных файлов
public void CleanupTempFiles()
{
var tempFiles = storage.GetFiles("temp");
foreach (var file in tempFiles)
{
// Удаляем только старые файлы
if (IsFileOlderThan(file, TimeSpan.FromDays(7)))
{
Console.WriteLine(storage.DeleteFile("", file) ? "Файл удален" : "Не удалось удалить файл");
}
}
}
🛠️ Вспомогательные функции
📂 Работа с путями
NormalizePath(string path)
Нормализует путь, заменяя обратные слеши и убирая двойные слеши.
// Примеры нормализации
var path1 = PlayerData.NormalizePath("C:\\Users\\ivan\\data");
// → "C:/Users/ivan/data"
var path2 = PlayerData.NormalizePath("folder//subfolder\\\\file.txt");
// → "folder/subfolder/file.txt"
var path3 = PlayerData.NormalizePath(@"app\data\");
// → "app/data/"
GetNameFile(string path)
Извлекает имя файла из пути.
// Получение имени файла
var fileName = PlayerData.GetNameFile("users/ivan/profile.dat");
// → "profile.dat"
var fileName2 = PlayerData.GetNameFile("C:/projects/report.pdf");
// → "report.pdf"
var fileName3 = PlayerData.GetNameFile("folder/subfolder/");
// → "" (пустая строка для папок)
GetNameDirectory(string path)
Извлекает имя последней папки из пути.
// Получение имени папки
var dirName = PlayerData.GetNameDirectory("users/ivan/profile.dat");
// → "ivan"
var dirName2 = PlayerData.GetNameDirectory("projects/2024/january/");
// → "january"
var dirName3 = PlayerData.GetNameDirectory("file.txt");
// → "" (пустая строка для файлов в корне)
GetPathToDirectory(string path)
Получает путь к родительской папке.
// Получение пути к родительской папке
var parentPath = PlayerData.GetPathToDirectory("users/ivan/profile.dat");
// → "users/ivan/"
var parentPath2 = PlayerData.GetPathToDirectory("projects/");
// → "projects/"
var parentPath3 = PlayerData.GetPathToDirectory("file.txt");
// → "" (корневая папка)
GetCutPath(string path, int keepRight = 1)
Оставляет только указанное количество сегментов пути справа.
// Сокращение пути
var shortPath = PlayerData.GetCutPath("projects/2024/january/report.pdf", 2);
// → "january/report.pdf"
var shortPath2 = PlayerData.GetCutPath("users/ivan/documents/contract.pdf", 1);
// → "contract.pdf"
var shortPath3 = PlayerData.GetCutPath("folder1/folder2/folder3/", 3);
// → "folder1/folder2/folder3/"
PrepareHashedPath(out string result, string encryptedPath, string unencryptedPath = "", params PathMode[] modes)
Метод подготавливает полный физический путь: хеширует сегменты encryptedPath и создаёт/проверяет структуру папок по заданным режимам.
Важно о последнем сегменте пути:
Если
encryptedPathуказывает на папку — рекомендуется заканчивать его слешем/(например,"users/ivan/documents/").
Это явно говорит методу, что последний сегмент — директория, и он может создать её (приEnsureDirectoryExists).Если слеш в конце отсутствует — метод считает последний сегмент файлом и не создаёт директорию с таким именем (даже при
EnsureDirectoryExists).Папки и файлы используют разные длины хэша (
LengthNameDirectoryиLengthNameFile).
Поэтому важно, чтобы метод правильно понял тип последнего сегмента: слеш/→ папка (длинаLengthNameDirectory), без слеша → файл (длинаLengthNameFile).Это сделано потому, что на этапе подготовки пути ещё не существует на диске, и не возможно автоматически определить тип последнего сегмента (файл или папка).
Параметры modes:
EnsureDirectoryExists— создавать отсутствующие папкиCleanConflictingFiles— удалять файлы, мешающие созданию папокSkipMissingDirectories— не останавливаться и не выбрасывать ошибку, если какая-то промежуточная директория отсутствует
string physicalPath;
bool success = storage.PrepareHashedPath(
out physicalPath,
encryptedPath: "users/ivan/documents",
unencryptedPath: "C:/myapp/data",
PathMode.EnsureDirectoryExists,
PathMode.CleanConflictingFiles
);
if (success)
{
Console.WriteLine($"Подготовлен путь: {physicalPath}");
// теперь можно работать напрямую с physicalPath
}
else
{
Console.WriteLine($"Подготовка прервана. Последний успешный путь: {physicalPath}");
// Здесь можно проверить, где именно остановилось создание
}
🔄 Конвертация объектов
Convert(object data) → byte[]
Сериализует любой объект в байты с помощью MessagePack.
// Сериализация объектов
var user = new { Name = "Иван", Age = 30 };
byte[] userBytes = PlayerData.Convert(user);
var settings = new AppSettings { Theme = "Dark" };
byte[] settingsBytes = PlayerData.Convert(settings);
// Работа с коллекциями
var numbers = new List<int> { 1, 2, 3, 4, 5 };
byte[] numbersBytes = PlayerData.Convert(numbers);
// Словари тоже поддерживаются
var dict = new Dictionary<string, string>
{
["key1"] = "value1",
["key2"] = "value2"
};
byte[] dictBytes = PlayerData.Convert(dict);
// Оптимизация с атрибутами MessagePack
[MessagePackObject]
public class OptimizedData
{
[Key(0)] public int Id { get; set; }
[Key(1)] public string Name { get; set; }
[Key(2)] public DateTime Created { get; set; }
}
var optimized = new OptimizedData { Id = 1, Name = "Test" };
byte[] optimizedBytes = PlayerData.Convert(optimized); // Более компактный формат
Convert<T>(byte[] data) → T
Десериализует байты обратно в объект указанного типа.
// Десериализация
byte[] userData = // ... полученные байты
var user = PlayerData.Convert<User>(userData);
// Работа с коллекциями
byte[] listData = // ... байты списка
var numbers = PlayerData.Convert<List<int>>(listData);
Convert(byte[] data, Type type) → object
Динамическая десериализация по типу.
// Динамическая десериализация
Type targetType = typeof(UserProfile);
byte[] data = // ... полученные байты
object result = PlayerData.Convert(data, targetType);
if (result is UserProfile profile)
{
Console.WriteLine($"Пользователь: {profile.Name}");
}
🔐 Шифрование и работа с сетью
🔒 Локальное шифрование
Encrypt(byte[] plaintext) → byte[]
Шифрует массив байтов
// Шифрование
var user = new { Name = "Иван", Password = "secret123" };
byte[] serialized = PlayerData.Convert(user);
byte[] encryptedUser = storage.Encrypt(serialized);
Decrypt(byte[] data) → byte[]
Расшифровывает массив байтов, зашифрованный методом Encrypt.
// Расшифровка и десериализация
byte[] encryptedUserData = // ... зашифрованные данные пользователя
byte[] decryptedData = storage.Decrypt(encryptedUserData);
var user = PlayerData.Convert<User>(decryptedData);
🌐 Сетевое взаимодействие
EncryptNetworkData(object data) → byte[]
Подготавливает объект для сетевой передачи: сериализует, шифрует и добавляет маркеры.
// Подготовка данных для отправки по сети
var message = new ChatMessage
{
Sender = "Иван",
Text = "Привет!",
Timestamp = DateTime.UtcNow
};
byte[] networkPacket = storage.EncryptNetworkData(message);
// → маркер_начало + зашифрованные_данные + маркер_конец
// Отправка через сокет
public async Task SendMessageAsync(NetworkStream stream, object data)
{
byte[] packet = storage.EncryptNetworkData(data);
await stream.WriteAsync(packet, 0, packet.Length);
Console.WriteLine($"Отправлено пакетов: {packet.Length} байт");
}
DecryptNetworkData<T>(ReadOnlyMemory<byte> data, Action<T> action)
Обрабатывает входящие сетевые данные, автоматически выделяя целые сообщения.
// Обработка входящих сетевых данных
public async Task ReceiveDataAsync(NetworkStream stream)
{
var buffer = new byte[8192];
var memoryStream = new MemoryStream();
while (true)
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
memoryStream.Write(buffer, 0, bytesRead);
// Обрабатываем все полные сообщения
var remaining = storage.DecryptNetworkData<ChatMessage>(memoryStream.ToArray(), message =>
{
Console.WriteLine($"[{message.Sender}]: {message.Text}");
ProcessMessage(message);
});
// Сохраняем неполное сообщение для следующего пакета
memoryStream.SetLength(0);
if (remaining.Length > 0)
memoryStream.Write(remaining.ToArray(), 0, remaining.Length);
}
}
📝 Логирование и обработка событий
🎯 Система логирования
📊 Уровни логирования (DataLogLevel)
// Все доступные уровни логирования
public enum DataLogLevel
{
Error = 0, // Критические ошибки
Warning = 1, // Предупреждения
Info = 2, // Информационные сообщения
Debug = 3, // Отладочная информация
Trace = 4 // Детальная трассировка
}
// Пример использования уровней
public void ConfigureLogging(DataLogLevel minLevel)
{
// Фильтрация по уровню
storage.Log += (logEvent) =>
{
if (logEvent.Level <= minLevel)
{
Console.WriteLine($"[{logEvent.Level}] {logEvent.Message}");
}
};
}
🔔 Событие Log
Подписка на события логирования
// Базовая подписка
var storage = new PlayerData("мой-секретный-ключ");
storage.Log += OnLogEvent;
// Обработчик событий
private void OnLogEvent(PlayerDataLogEvent logEvent)
{
Console.WriteLine($"[{logEvent.Timestamp:HH:mm:ss}] {logEvent.Level}: {logEvent.Message}");
if (logEvent.Exception != null)
{
Console.WriteLine($"Исключение: {logEvent.Exception.Message}");
Console.WriteLine($"Стек: {logEvent.Exception.StackTrace}");
}
}
// Несколько обработчиков
storage.Log += LogToConsole;
storage.Log += LogToFile;
// Отписка от события
storage.Log -= LogToConsole;
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- MessagePack (>= 3.1.4)
-
net10.0
- MessagePack (>= 3.1.4)
-
net8.0
- MessagePack (>= 3.1.4)
-
net9.0
- MessagePack (>= 3.1.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.