20230409
This commit is contained in:
parent
66b3a8cc77
commit
b2ea5c61d1
@ -7,6 +7,24 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<RootNamespace>FileSplitter.Console</RootNamespace>
|
<RootNamespace>FileSplitter.Console</RootNamespace>
|
||||||
<AssemblyName>FileSplitter</AssemblyName>
|
<AssemblyName>FileSplitter</AssemblyName>
|
||||||
|
<PackageId>FileSplitter</PackageId>
|
||||||
|
<Title>ANB Software File Splitter Console</Title>
|
||||||
|
<Version>2023.04.09</Version>
|
||||||
|
<Authors>Alexander Babaev</Authors>
|
||||||
|
<Product>ANB Software File Splitter</Product>
|
||||||
|
<Description>Console App for ANB Software File Splitter. Split and join any file.</Description>
|
||||||
|
<Copyright>Alexander Babaev</Copyright>
|
||||||
|
<PackageProjectUrl>https://git.babaev-an.ru/babaev-an/FileSplitter</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://git.babaev-an.ru/babaev-an/FileSplitter.git</RepositoryUrl>
|
||||||
|
<NeutralLanguage>ru</NeutralLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ANBSoftware.ComponentsPack" Version="2023.409.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FileSplitterShared\FileSplitterShared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,66 +1,128 @@
|
|||||||
//Приветственное сообщение
|
using System.Reflection;
|
||||||
Console.WriteLine("ANB Software Делитель файлов");
|
|
||||||
Console.WriteLine("в. 2023.04.08");
|
|
||||||
|
|
||||||
//Вывожу помощь
|
using anbs_cp.Classes;
|
||||||
Help();
|
|
||||||
|
|
||||||
//Команда
|
using FileSplitter.Shared.Classes;
|
||||||
string command;
|
using FileSplitter.Shared.Enums;
|
||||||
|
|
||||||
//Начинаю цикл
|
string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
||||||
do
|
|
||||||
|
//Инициализирую список параметров
|
||||||
|
ConsoleParamsParser consoleParser = new(Environment.GetCommandLineArgs());
|
||||||
|
|
||||||
|
//Приветственное сообщение
|
||||||
|
Console.WriteLine("********************************************************************************");
|
||||||
|
Console.WriteLine($"\t{Localization.AppTitle}");
|
||||||
|
Console.WriteLine($"\t{string.Format(Localization.AppVersion, assemblyVersion)}");
|
||||||
|
Console.WriteLine(
|
||||||
|
$"\t{string.Format(Localization.AppCopyrights, DateTime.Now.Year == 2023 ? "2023" : $"2023 - {DateTime.Now.Year}")}");
|
||||||
|
Console.WriteLine("********************************************************************************");
|
||||||
|
|
||||||
|
//Прерываем, если нет параметров
|
||||||
|
if (!consoleParser.HasParam("split") && !consoleParser.HasParam("join"))
|
||||||
{
|
{
|
||||||
//Запрос команды
|
Console.WriteLine(Localization.MessageNoParameters);
|
||||||
Console.WriteLine("Введите команду:");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Считывание команды
|
//Разделение файлов
|
||||||
command = (Console.ReadLine() ?? "").ToLower();
|
if (consoleParser.HasParam("split"))
|
||||||
|
FileSplit(consoleParser);
|
||||||
|
|
||||||
//Выбор действия
|
//Соединение файлов
|
||||||
switch (command)
|
if (consoleParser.HasParam("join"))
|
||||||
|
FileJoin(consoleParser);
|
||||||
|
|
||||||
|
//Функция разделения файлов
|
||||||
|
static void FileSplit (ConsoleParamsParser @params)
|
||||||
|
{
|
||||||
|
//Проверяю наличие параметров
|
||||||
|
if (!@params.HasParam("-fn") || !@params.HasParam("-td") || !@params.HasParam("-ps"))
|
||||||
{
|
{
|
||||||
////Если команда "Шифровка"
|
//- вывожу сообщение
|
||||||
//case "crypt" or "c":
|
Console.WriteLine(Localization.MessageNoParametersForSplit);
|
||||||
// //Запускаю сценарий шифровки
|
|
||||||
// await CryptAsync();
|
//- прерываю
|
||||||
// break;
|
return;
|
||||||
////Если команда "Дешифровка"
|
|
||||||
//case "delete" or "d":
|
|
||||||
// //Запускаю сценарий дешифровки
|
|
||||||
// await DecryptAsync();
|
|
||||||
// break;
|
|
||||||
////Если команда "Установочные файлы"
|
|
||||||
//case "ifiles" or "i":
|
|
||||||
// //Запускаю сценарий создания установочных файлов
|
|
||||||
// await CreateInstallFilesInfoAsync();
|
|
||||||
// break;
|
|
||||||
////Если команда "Помощь"
|
|
||||||
//case "help" or "h":
|
|
||||||
// //Запускаю сценарий помощи
|
|
||||||
// Help();
|
|
||||||
// break;
|
|
||||||
//Если что-то другое
|
|
||||||
default:
|
|
||||||
//Вывожу сообщение об ошибке, если команда не "Выход"
|
|
||||||
if (command is not ("exit" or "e"))
|
|
||||||
Console.WriteLine("Команда не опознана! Повторите попытку ещё раз, введите [h]elp для помощи или введите [e]xit для выхода...");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} while (command is not ("exit" or "e"));
|
|
||||||
|
|
||||||
static void SplitFile(string path)
|
//Получаю параметры
|
||||||
{
|
//- имя исходного файла
|
||||||
|
string fileName = @params.GetValue("-fn") ?? string.Empty;
|
||||||
|
//- папка для сохранения разбиения
|
||||||
|
string targetDir = @params.GetValue("-td") ?? string.Empty;
|
||||||
|
//- размер части
|
||||||
|
long partSize = TypeConverter.StrToInt64(@params.GetValue("-ps") ?? string.Empty);
|
||||||
|
//- параметры
|
||||||
|
List<FileSplitOptions> options = new();
|
||||||
|
|
||||||
|
//Проверяю параметры разбиения
|
||||||
|
//- отключена ли проверка хэша
|
||||||
|
if (@params.HasParam("/NoCheckHash"))
|
||||||
|
options.Add(FileSplitOptions.fsoNoCheckHash);
|
||||||
|
//- нужно ли удалять исходный файл
|
||||||
|
if (@params.HasParam("/DeleteSource"))
|
||||||
|
options.Add(FileSplitOptions.fsoDeleteSourceFileAfterSplit);
|
||||||
|
//- нужно ли шифровать файл информации
|
||||||
|
if (@params.HasParam("/EncryptInfoFile"))
|
||||||
|
options.Add(FileSplitOptions.fsoEncryptInfoFile);
|
||||||
|
|
||||||
|
//Функция прогресса
|
||||||
|
#pragma warning disable CS8622
|
||||||
|
FileSplitterClass.OnProgress += OnProgress;
|
||||||
|
#pragma warning restore CS8622
|
||||||
|
|
||||||
|
//Выполняю разбиение
|
||||||
|
FileSplitterClass.SplitFile(fileName, targetDir, partSize, options.AsReadOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Информация о работе с программой
|
//Функция объединения
|
||||||
static void Help ()
|
static void FileJoin (ConsoleParamsParser @params)
|
||||||
{
|
{
|
||||||
//Публикую сообщение о работе с программой
|
//Проверяю наличие параметров
|
||||||
Console.WriteLine("Информация о работе с программой:\n\t" +
|
if (!@params.HasParam("-ifn") || !@params.HasParam("-tfn"))
|
||||||
"[c]rypt - шифровка архива\n\t" +
|
{
|
||||||
"[d]ecrypt - дешифровка архива\n\t" +
|
//- вывожу сообщение
|
||||||
"[i]files - создание списка установочных файлов\n\t" +
|
Console.WriteLine(Localization.MessageNoParametersForSplit);
|
||||||
"[e]xit - Выход из программы\n\t[h]elp - Повторный вывод этого сообщения.");
|
|
||||||
|
//- прерываю
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Получаю параметры
|
||||||
|
//- имя файла с информацией о разбиении
|
||||||
|
string infoFileName = @params.GetValue("-ifn") ?? string.Empty;
|
||||||
|
//- имя целевого файла
|
||||||
|
string targetFileName = @params.GetValue("-tfn") ?? string.Empty;
|
||||||
|
//- параметры
|
||||||
|
List<FileJoinOptions> options = new();
|
||||||
|
|
||||||
|
//Проверяю параметры разбиения
|
||||||
|
//- отключена ли проверка хэша
|
||||||
|
if (@params.HasParam("/NoCheckHash"))
|
||||||
|
options.Add(FileJoinOptions.fjoNoCheckHash);
|
||||||
|
//- нужно ли удалять исходные файлы
|
||||||
|
if (@params.HasParam("/DeleteSource"))
|
||||||
|
options.Add(FileJoinOptions.fjoDeleteSourceFilesAfterJoin);
|
||||||
|
//- нужно ли дешифровать файл информации
|
||||||
|
if (@params.HasParam("/DecryptInfoFile"))
|
||||||
|
options.Add(FileJoinOptions.fjoInfoFileIsEncrypted);
|
||||||
|
//- нужно ли отключить проверку версии файла информации
|
||||||
|
if (@params.HasParam("/IgnoreVersion"))
|
||||||
|
options.Add(FileJoinOptions.fjoIgnoreSupportedScriptVersion);
|
||||||
|
|
||||||
|
//Функция прогресса
|
||||||
|
#pragma warning disable CS8622
|
||||||
|
FileSplitterClass.OnProgress += OnProgress;
|
||||||
|
#pragma warning restore CS8622
|
||||||
|
|
||||||
|
//Выполняю объединение
|
||||||
|
FileSplitterClass.JoinFile(infoFileName, targetFileName, options.AsReadOnly());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Функция вывода прогресса
|
||||||
|
static void OnProgress (object sender, FileSplitterOnProgress args)
|
||||||
|
{
|
||||||
|
//Вывод сообщения в консоль
|
||||||
|
Console.WriteLine(args.Message);
|
||||||
}
|
}
|
7
FileSplitterProj.sln.DotSettings
Normal file
7
FileSplitterProj.sln.DotSettings
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0411_0430_0431_0430_0435_0432/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0440_0430_0437_0434_0435_043B_0451_043D_043D_044B_0435/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0440_0430_0437_0434_0435_043B_0451_043D_043D_044B_043C_0438/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0440_0430_0437_0434_0435_043B_0451_043D_043D_044B_0445/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0441_043E_0437_0434_0430_0451_043C/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0445_044D_0448_0430/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
@ -5,20 +5,27 @@ namespace FileSplitter.Shared.Classes;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Информация о разбиении
|
/// Информация о разбиении
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FileSplitInfo
|
public sealed class FileSplitInfo
|
||||||
{
|
{
|
||||||
|
public FileSplitInfo()
|
||||||
|
{
|
||||||
|
SplitFiles = new();
|
||||||
|
TargetFile = new TargetFileInfo();
|
||||||
|
FileSplitterVersion = FileSplitterConstants.CurrentSplitterVersion;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Версия программы, необходимая для сборки файла
|
/// Версия программы, необходимая для сборки файла
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? FileSplitterVersion { get; set; }
|
public string FileSplitterVersion { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Информация о собираемом файле
|
/// Информация о собираемом файле
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ITargetFileInfo? TargetFile { get; set; }
|
public TargetFileInfo TargetFile { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Информация о частях файла
|
/// Информация о частях файла
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ISplitFile>? SplitFiles { get; set; }
|
public List<SplitFile> SplitFiles { get; set; }
|
||||||
}
|
}
|
346
FileSplitterShared/Classes/FileSplitterClass.cs
Normal file
346
FileSplitterShared/Classes/FileSplitterClass.cs
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using anbs_cp.Classes;
|
||||||
|
using anbs_cp.Classes.Encrypt;
|
||||||
|
|
||||||
|
using FileSplitter.Shared.Enums;
|
||||||
|
using FileSplitter.Shared.Interfaces;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace FileSplitter.Shared.Classes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Класс операций
|
||||||
|
/// </summary>
|
||||||
|
public static class FileSplitterClass
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Событие прогресса
|
||||||
|
/// </summary>
|
||||||
|
public static event EventHandler<FileSplitterOnProgress>? OnProgress;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Разделение файла на части
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">Имя файла для разделения</param>
|
||||||
|
/// <param name="targetDir">Папка, в которую нужно сохранить файлы</param>
|
||||||
|
/// <param name="partSize">Размер части в байтах</param>
|
||||||
|
/// <param name="options">Параметры разбиения</param>
|
||||||
|
public static void SplitFile (string fileName, string targetDir, long partSize, ReadOnlyCollection<FileSplitOptions> options)
|
||||||
|
{
|
||||||
|
//Задаю обработчик для распаковки
|
||||||
|
EventHandler<FileSplitterOnProgress>? onProgressEvent = OnProgress;
|
||||||
|
|
||||||
|
//Инициализирующее сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
string.Format(Localization.MessageStartSplit, fileName,
|
||||||
|
new FileSizeConverter(Localization.FileSizeStrings).Convert(partSize),
|
||||||
|
targetDir
|
||||||
|
)));
|
||||||
|
|
||||||
|
//Создаю результат
|
||||||
|
FileSplitInfo splitInfo = new()
|
||||||
|
{
|
||||||
|
FileSplitterVersion = FileSplitterConstants.CurrentSplitterVersion
|
||||||
|
};
|
||||||
|
|
||||||
|
//Если целевая папка не создана
|
||||||
|
if (!Directory.Exists(targetDir))
|
||||||
|
//- то создаём её
|
||||||
|
Directory.CreateDirectory(targetDir);
|
||||||
|
|
||||||
|
//Получаю размер текущего файла
|
||||||
|
long fileSize = FileExtension.FileSize(fileName);
|
||||||
|
|
||||||
|
//Получаю информацию о целевом файле
|
||||||
|
splitInfo.TargetFile = new()
|
||||||
|
{
|
||||||
|
FileName = Path.GetFileName(fileName),
|
||||||
|
FileSize = fileSize,
|
||||||
|
FileHash = new FileHash(fileName).Hash,
|
||||||
|
// ReSharper disable once PossibleLossOfFraction
|
||||||
|
SplitCount = (long)Math.Round(fileSize / (decimal)partSize, MidpointRounding.ToPositiveInfinity)
|
||||||
|
};
|
||||||
|
|
||||||
|
//Открываю файл
|
||||||
|
BinaryReader fileReader = new(File.Open(fileName, FileMode.Open));
|
||||||
|
|
||||||
|
//Разделяю файлы
|
||||||
|
for (int i = 0; i < splitInfo.TargetFile.SplitCount; i++)
|
||||||
|
{
|
||||||
|
//Сообщение прогресса
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(i + 1, splitInfo.TargetFile.SplitCount,
|
||||||
|
string.Format(Localization.MessageSplitFilePart, i + 1, splitInfo.TargetFile.SplitCount)));
|
||||||
|
|
||||||
|
//Имя части
|
||||||
|
string partName = $"{Path.GetFileName(fileName)}.part{i + 1}.fsf";
|
||||||
|
//Полный путь к файлу части
|
||||||
|
string partFileName = $"{LikeDelphi.IncludeTrailingBackslash(targetDir)}{partName}";
|
||||||
|
|
||||||
|
//Смещение части от начала исходного файла
|
||||||
|
int startPos = (int)(i * partSize);
|
||||||
|
|
||||||
|
//Размер части
|
||||||
|
long bufferSize = fileSize - startPos > 0 ? partSize : partSize + (fileSize - startPos);
|
||||||
|
|
||||||
|
//Считываю значения
|
||||||
|
byte[] buffer = fileReader.ReadBytes((int)bufferSize);
|
||||||
|
|
||||||
|
//Записываю значение в файл
|
||||||
|
//- открываю файл
|
||||||
|
BinaryWriter fileWriter = new(File.Create(partFileName, (int)bufferSize));
|
||||||
|
//- записываю файл
|
||||||
|
fileWriter.Write(buffer);
|
||||||
|
//- закрываю файл
|
||||||
|
fileWriter.Close();
|
||||||
|
|
||||||
|
//Создаю информацию о части
|
||||||
|
SplitFile fileInfo = new()
|
||||||
|
{
|
||||||
|
Num = i + 1,
|
||||||
|
Offset = startPos,
|
||||||
|
Size = new FileInfo(partFileName).Length,
|
||||||
|
Hash = new FileHash(partFileName).Hash
|
||||||
|
};
|
||||||
|
|
||||||
|
//Добавляю в файл информации
|
||||||
|
splitInfo.SplitFiles.Add(fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Закрываю исходный файл
|
||||||
|
fileReader.Close();
|
||||||
|
//- и освобождаю память
|
||||||
|
fileReader.Dispose();
|
||||||
|
|
||||||
|
//Инициализирующее сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
string.Format(Localization.MessageSplitComplete, fileName)));
|
||||||
|
|
||||||
|
//Проверка сумм
|
||||||
|
if (!options.Contains(FileSplitOptions.fsoNoCheckHash))
|
||||||
|
//- и если не прошли проверку
|
||||||
|
if (!CheckHash(targetDir, Path.GetFileName(fileName), splitInfo.SplitFiles))
|
||||||
|
//- то удаляем файлы разбиения
|
||||||
|
DeleteSplitFiles(Path.GetFileName(fileName), targetDir, splitInfo.TargetFile.SplitCount);
|
||||||
|
|
||||||
|
//Имя файла информации о разбиении
|
||||||
|
string reportFileName = $"{LikeDelphi.IncludeTrailingBackslash(targetDir)}{Path.GetFileName(fileName)}.fsi";
|
||||||
|
|
||||||
|
//Записываю информацию о разбиении
|
||||||
|
//- создаю файл
|
||||||
|
StreamWriter writer = new(reportFileName, Encoding.UTF8, new() { Access = FileAccess.Write, Mode = FileMode.Create });
|
||||||
|
//- создаю данные для записи файла
|
||||||
|
string data = options.Contains(FileSplitOptions.fsoEncryptInfoFile)
|
||||||
|
? StringEncrypt.Encrypt(JsonConvert.SerializeObject(splitInfo))
|
||||||
|
: JsonConvert.SerializeObject(splitInfo);
|
||||||
|
//- записываю в файл
|
||||||
|
writer.WriteLine(data);
|
||||||
|
//- закрываю файл
|
||||||
|
writer.Close();
|
||||||
|
//- освобождаю память
|
||||||
|
writer.Dispose();
|
||||||
|
|
||||||
|
//Если в опциях активирована опция удаления исходного файла
|
||||||
|
if (options.Contains(FileSplitOptions.fsoDeleteSourceFileAfterSplit))
|
||||||
|
//- то удаляю его
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Объединение разъединенного файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="infoFileName">Имя файла с информацией о разделении</param>
|
||||||
|
/// <param name="targetFileName">Целевой файл</param>
|
||||||
|
/// <param name="options">Параметры объединения</param>
|
||||||
|
public static void JoinFile (string infoFileName, string targetFileName, ReadOnlyCollection<FileJoinOptions> options)
|
||||||
|
{
|
||||||
|
//Задаю обработчик для распаковки
|
||||||
|
EventHandler<FileSplitterOnProgress>? onProgressEvent = OnProgress;
|
||||||
|
|
||||||
|
//Инициализирующее сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
string.Format(Localization.MessageStartJoin, infoFileName, targetFileName)));
|
||||||
|
|
||||||
|
//Открываю файл для чтения
|
||||||
|
StreamReader reader = new(infoFileName, Encoding.UTF8);
|
||||||
|
|
||||||
|
//Читаю строку
|
||||||
|
string tLine = reader.ReadLine() ?? "{}";
|
||||||
|
|
||||||
|
//Освобождаю reader
|
||||||
|
reader.Close();
|
||||||
|
reader.Dispose();
|
||||||
|
|
||||||
|
//Содержимое файла информации о разбиении
|
||||||
|
string jsonData = options.Contains(FileJoinOptions.fjoInfoFileIsEncrypted)
|
||||||
|
? StringEncrypt.Decrypt(tLine)
|
||||||
|
: tLine;
|
||||||
|
|
||||||
|
//Создаю переменную для информации о разбиении
|
||||||
|
FileSplitInfo splitInfo = new();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Получаю информацию о разбиении
|
||||||
|
splitInfo = JsonConvert.DeserializeObject<FileSplitInfo>(jsonData) ?? splitInfo;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0, Localization.MessageJoinUnknownFile));
|
||||||
|
Environment.Exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Проверяю версию
|
||||||
|
if (!options.Contains(FileJoinOptions.fjoIgnoreSupportedScriptVersion) &&
|
||||||
|
!FileSplitterConstants.SupportSplitterVersion.Contains(splitInfo.FileSplitterVersion))
|
||||||
|
{
|
||||||
|
//Вывожу сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0, string.Format(Localization.MessageJoinUnsupportedFile, splitInfo.FileSplitterVersion)));
|
||||||
|
|
||||||
|
//Прерываю
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Получаю папку с разделёнными файлами
|
||||||
|
string sourceDir = LikeDelphi.IncludeTrailingBackslash(Path.GetDirectoryName(infoFileName) ?? "");
|
||||||
|
|
||||||
|
//Проверяю хэш
|
||||||
|
if (!options.Contains(FileJoinOptions.fjoNoCheckHash) && !CheckHash(sourceDir,
|
||||||
|
Path.GetFileName(splitInfo.TargetFile.FileName), splitInfo.SplitFiles))
|
||||||
|
{
|
||||||
|
//Вывожу сообщение
|
||||||
|
onProgressEvent?.Invoke(null, new(0, 0, Localization.MessageJoinHashError));
|
||||||
|
|
||||||
|
//Прерываю
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Открываю файл
|
||||||
|
BinaryWriter fileWriter = new(File.Create(targetFileName, (int)splitInfo.TargetFile.FileSize));
|
||||||
|
|
||||||
|
//Объединяю файлы
|
||||||
|
for (int i = 1; i <= splitInfo.TargetFile.SplitCount; i++)
|
||||||
|
{
|
||||||
|
//Вывожу сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(i, splitInfo.TargetFile.SplitCount,
|
||||||
|
string.Format(Localization.MessageJoinFilePart, i, splitInfo.TargetFile.SplitCount)));
|
||||||
|
|
||||||
|
//Имя файла части
|
||||||
|
string partFileName = $"{sourceDir}{Path.GetFileName(splitInfo.TargetFile.FileName)}.part{i}.fsf";
|
||||||
|
|
||||||
|
//Параметры части
|
||||||
|
ISplitFile partInfo = splitInfo.SplitFiles.FirstOrDefault(file => file.Num == i) ?? new SplitFile();
|
||||||
|
|
||||||
|
//Читаю часть
|
||||||
|
//- открываю файл для чтения
|
||||||
|
BinaryReader fileReader = new(File.Open(partFileName, FileMode.Open));
|
||||||
|
//- считываю содержимое
|
||||||
|
byte[] buffer = fileReader.ReadBytes((int)partInfo.Size);
|
||||||
|
//- закрываю файл
|
||||||
|
fileReader.Close();
|
||||||
|
//- освобождаю память
|
||||||
|
fileReader.Dispose();
|
||||||
|
|
||||||
|
//Записываю часть в общий файл
|
||||||
|
fileWriter.Write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Закрываю целевой файл
|
||||||
|
fileWriter.Close();
|
||||||
|
//Освобождаю память
|
||||||
|
fileWriter.Dispose();
|
||||||
|
|
||||||
|
//Вывожу сообщение
|
||||||
|
onProgressEvent?.Invoke(null, new(0, 0, Localization.MessageJoinComplete));
|
||||||
|
|
||||||
|
//Удаляю разделённые файлы
|
||||||
|
if (options.Contains(FileJoinOptions.fjoDeleteSourceFilesAfterJoin))
|
||||||
|
DeleteSplitFiles(splitInfo.TargetFile.FileName, sourceDir, splitInfo.TargetFile.SplitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление разделённых файлов
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">Исходное имя файла (без пути!)</param>
|
||||||
|
/// <param name="targetDir">Целевая директория</param>
|
||||||
|
/// <param name="splitCount">Число разбиения</param>
|
||||||
|
private static void DeleteSplitFiles (string fileName, string targetDir, long splitCount)
|
||||||
|
{
|
||||||
|
//Перебираю части
|
||||||
|
for (int i = 1; i < splitCount; i++)
|
||||||
|
{
|
||||||
|
//Имя части
|
||||||
|
string partName = $"{fileName}.part{i}.fsf";
|
||||||
|
//Полный путь к файлу части
|
||||||
|
string partFileName = $"{LikeDelphi.IncludeTrailingBackslash(targetDir)}{partName}";
|
||||||
|
|
||||||
|
//Удаляю файл
|
||||||
|
File.Delete(partFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Имя файла информации о разбиении
|
||||||
|
string reportFileName = $"{LikeDelphi.IncludeTrailingBackslash(targetDir)}{Path.GetFileName(fileName)}.fsi";
|
||||||
|
|
||||||
|
//Удаляю файл информации
|
||||||
|
File.Delete(reportFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проверяет соответствие хэша файлов
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseDir">Базовая папка с файлами</param>
|
||||||
|
/// <param name="baseName">Базовое имя файлов</param>
|
||||||
|
/// <param name="fileList">Список параметров файлов разбиения</param>
|
||||||
|
/// <returns>Прошли ли файлы проверку</returns>
|
||||||
|
private static bool CheckHash (string baseDir, string baseName, List<SplitFile> fileList)
|
||||||
|
{
|
||||||
|
//Задаю обработчик для распаковки
|
||||||
|
EventHandler<FileSplitterOnProgress>? onProgressEvent = OnProgress;
|
||||||
|
|
||||||
|
//Инициализирующее сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
Localization.MessageHashCheckStart));
|
||||||
|
|
||||||
|
//Перебираю все части
|
||||||
|
foreach (SplitFile file in fileList)
|
||||||
|
{
|
||||||
|
//Полный путь к файлу части
|
||||||
|
string partFileName = $"{LikeDelphi.IncludeTrailingBackslash(baseDir)}{baseName}.part{file.Num}.fsf";
|
||||||
|
|
||||||
|
//Получаю хэш
|
||||||
|
IStructuralEquatable fileHashEq = new FileHash(partFileName).Hash;
|
||||||
|
|
||||||
|
//Если не равен
|
||||||
|
if (!fileHashEq.Equals(file.Hash, StructuralComparisons.StructuralEqualityComparer))
|
||||||
|
{
|
||||||
|
//- то сообщаю
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
string.Format(Localization.MessageHashCheckFail, partFileName)));
|
||||||
|
|
||||||
|
//- и прерываю
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Везде хэш был равен
|
||||||
|
//- выдаю сообщение
|
||||||
|
onProgressEvent?.Invoke(null,
|
||||||
|
new(0, 0,
|
||||||
|
Localization.MessageHashCheckComplete));
|
||||||
|
|
||||||
|
//- и возвращаю результат
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
17
FileSplitterShared/Classes/FileSplitterConstants.cs
Normal file
17
FileSplitterShared/Classes/FileSplitterConstants.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace FileSplitter.Shared.Classes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Неизменяемые константы программы
|
||||||
|
/// </summary>
|
||||||
|
public static class FileSplitterConstants
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Текущая версия информационного файла
|
||||||
|
/// </summary>
|
||||||
|
public static string CurrentSplitterVersion = "20230409";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Все поддерживаемые версии информационного файла
|
||||||
|
/// </summary>
|
||||||
|
public static string[] SupportSplitterVersion = { "20230409" };
|
||||||
|
}
|
35
FileSplitterShared/Classes/FileSplitterOnProgress.cs
Normal file
35
FileSplitterShared/Classes/FileSplitterOnProgress.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
namespace FileSplitter.Shared.Classes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Параметры события OnProgress
|
||||||
|
/// </summary>
|
||||||
|
public class FileSplitterOnProgress: EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Конструктор
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="current">Текущий прогресс</param>
|
||||||
|
/// <param name="total">Максимальные прогресс</param>
|
||||||
|
/// <param name="message">Сообщение</param>
|
||||||
|
public FileSplitterOnProgress (long current, long total, string message)
|
||||||
|
{
|
||||||
|
CurrentProgress = current;
|
||||||
|
MaxProgress = total;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Текущий прогресс
|
||||||
|
/// </summary>
|
||||||
|
public long CurrentProgress { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Максимальные прогресс
|
||||||
|
/// </summary>
|
||||||
|
public long MaxProgress { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сообщение
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; }
|
||||||
|
}
|
31
FileSplitterShared/Classes/Localization.cs
Normal file
31
FileSplitterShared/Classes/Localization.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
namespace FileSplitter.Shared.Classes;
|
||||||
|
|
||||||
|
public static class Localization
|
||||||
|
{
|
||||||
|
//Параметры приложения
|
||||||
|
public const string AppTitle = "ANB Software Делитель файлов";
|
||||||
|
public const string AppVersion = "Версия: {0}";
|
||||||
|
public const string AppCopyrights = "Авторские права (C) {0}, Александр Бабаев.";
|
||||||
|
|
||||||
|
//Сообщения
|
||||||
|
public const string MessageNoParameters =
|
||||||
|
"Нет параметров. Информацию о работе с программой смотрите в файле \"Help\\Russian\\Console.html\"";
|
||||||
|
public const string MessageNoParametersForSplit =
|
||||||
|
"Не заданы параметры разбиения. Информацию о работе с программой смотрите в файле \"Help\\Russian\\Console.html\"";
|
||||||
|
public const string MessageStartSplit = "Запущено разбиение файла {0} на части размером {1} и сохранением их в директории {2}.";
|
||||||
|
public const string MessageSplitFilePart = "Идёт обработка части {0} из {1}...";
|
||||||
|
public const string MessageSplitComplete = "Разбиение файла {0} завершено!";
|
||||||
|
public const string MessageHashCheckStart = "Начинаю проверку хэша разбиения";
|
||||||
|
public const string MessageHashCheckFail = "К сожалению, файл \"{0}\" не прошёл проверку хэша!";
|
||||||
|
public const string MessageHashCheckComplete = "Проверка хэша завершена!";
|
||||||
|
public const string MessageStartJoin = "Запущено объединение файлов, заданных файлом информации {0}, в файл {1}.";
|
||||||
|
public const string MessageJoinUnsupportedFile = "К сожалению, версия файла информации {0} не поддерживается!";
|
||||||
|
public const string MessageJoinUnknownFile = "Не могу прочитать файл информации! Возможно он зашифрован?";
|
||||||
|
public const string MessageJoinHashError = "К сожалению, разделённые файлы не прошли проверку. Возможно они повреждены?";
|
||||||
|
public const string MessageJoinFilePart = "Идёт обработка части {0} из {1}...";
|
||||||
|
public const string MessageJoinComplete = "Объединение файла {0} завершено!";
|
||||||
|
|
||||||
|
|
||||||
|
//Константы размеров
|
||||||
|
public static readonly string[] FileSizeStrings = { "байт", "Кб", "Мб", "Гб", "Тб" };
|
||||||
|
}
|
@ -5,12 +5,12 @@ namespace FileSplitter.Shared.Classes;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Разделенный файл
|
/// Разделенный файл
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SplitFile: ISplitFile
|
public sealed class SplitFile: ISplitFile
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Порядок части
|
/// Порядок части
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte Num { get; set; }
|
public int Num { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Размер части
|
/// Размер части
|
||||||
|
@ -5,12 +5,21 @@ namespace FileSplitter.Shared.Classes;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Информация о целевом файле
|
/// Информация о целевом файле
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TargetFileInfo: ITargetFileInfo
|
public sealed class TargetFileInfo: ITargetFileInfo
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Конструктор
|
||||||
|
/// </summary>
|
||||||
|
internal TargetFileInfo()
|
||||||
|
{
|
||||||
|
FileName = string.Empty;
|
||||||
|
FileHash = new byte[]{};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Имя файла
|
/// Имя файла
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Размер файла
|
/// Размер файла
|
||||||
@ -20,10 +29,10 @@ public class TargetFileInfo: ITargetFileInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// md5-сумма файла для проверки
|
/// md5-сумма файла для проверки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? FileHash { get; set; }
|
public byte[] FileHash { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Количество частей
|
/// Количество частей
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte SplitCount { get; set; }
|
public long SplitCount { get; set; }
|
||||||
}
|
}
|
27
FileSplitterShared/Enums/FileJoinOptions.cs
Normal file
27
FileSplitterShared/Enums/FileJoinOptions.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace FileSplitter.Shared.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Опции объединения файла
|
||||||
|
/// </summary>
|
||||||
|
public enum FileJoinOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Не проверять контрольную сумму перед началом объединения
|
||||||
|
/// </summary>
|
||||||
|
fjoNoCheckHash = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Json-Файл информации о разбиении зашифрован
|
||||||
|
/// </summary>
|
||||||
|
fjoInfoFileIsEncrypted = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удалить исходные файлы после объединения
|
||||||
|
/// </summary>
|
||||||
|
fjoDeleteSourceFilesAfterJoin = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Игнорировать не поддерживаемую версию файла информации
|
||||||
|
/// </summary>
|
||||||
|
fjoIgnoreSupportedScriptVersion = 3
|
||||||
|
}
|
22
FileSplitterShared/Enums/FileSplitOptions.cs
Normal file
22
FileSplitterShared/Enums/FileSplitOptions.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace FileSplitter.Shared.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Опции разделения файла
|
||||||
|
/// </summary>
|
||||||
|
public enum FileSplitOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Не проверять контрольную сумму после создания всех частей
|
||||||
|
/// </summary>
|
||||||
|
fsoNoCheckHash = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Шифровать json-Файл информации о разбиении
|
||||||
|
/// </summary>
|
||||||
|
fsoEncryptInfoFile = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удалить исходный файл после разбиения
|
||||||
|
/// </summary>
|
||||||
|
fsoDeleteSourceFileAfterSplit = 2
|
||||||
|
}
|
@ -8,4 +8,9 @@
|
|||||||
<RootNamespace>FileSplitter.Shared</RootNamespace>
|
<RootNamespace>FileSplitter.Shared</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ANBSoftware.ComponentsPack" Version="2023.409.2" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -8,7 +8,7 @@ public interface ISplitFile
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Порядок части
|
/// Порядок части
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte Num { get; set; }
|
public int Num { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Размер части
|
/// Размер части
|
||||||
|
@ -8,7 +8,7 @@ public interface ITargetFileInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Имя файла
|
/// Имя файла
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Размер файла
|
/// Размер файла
|
||||||
@ -18,10 +18,10 @@ public interface ITargetFileInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// md5-сумма файла для проверки
|
/// md5-сумма файла для проверки
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[]? FileHash { get; set; }
|
public byte[] FileHash { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Количество частей
|
/// Количество частей
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte SplitCount { get; set; }
|
public long SplitCount { get; set; }
|
||||||
}
|
}
|
BIN
output/x32/FileSplitter.exe
Normal file
BIN
output/x32/FileSplitter.exe
Normal file
Binary file not shown.
BIN
output/x32/sni.dll
Normal file
BIN
output/x32/sni.dll
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user