20230409
This commit is contained in:
parent
66b3a8cc77
commit
b2ea5c61d1
@ -7,6 +7,24 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>FileSplitter.Console</RootNamespace>
|
||||
<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>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ANBSoftware.ComponentsPack" Version="2023.409.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileSplitterShared\FileSplitterShared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,66 +1,128 @@
|
||||
//Приветственное сообщение
|
||||
Console.WriteLine("ANB Software Делитель файлов");
|
||||
Console.WriteLine("в. 2023.04.08");
|
||||
using System.Reflection;
|
||||
|
||||
//Вывожу помощь
|
||||
Help();
|
||||
using anbs_cp.Classes;
|
||||
|
||||
//Команда
|
||||
string command;
|
||||
using FileSplitter.Shared.Classes;
|
||||
using FileSplitter.Shared.Enums;
|
||||
|
||||
//Начинаю цикл
|
||||
do
|
||||
string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? string.Empty;
|
||||
|
||||
//Инициализирую список параметров
|
||||
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("Введите команду:");
|
||||
|
||||
//Считывание команды
|
||||
command = (Console.ReadLine() ?? "").ToLower();
|
||||
|
||||
//Выбор действия
|
||||
switch (command)
|
||||
{
|
||||
////Если команда "Шифровка"
|
||||
//case "crypt" or "c":
|
||||
// //Запускаю сценарий шифровки
|
||||
// await CryptAsync();
|
||||
// break;
|
||||
////Если команда "Дешифровка"
|
||||
//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)
|
||||
{
|
||||
|
||||
Console.WriteLine(Localization.MessageNoParameters);
|
||||
return;
|
||||
}
|
||||
|
||||
//Информация о работе с программой
|
||||
static void Help ()
|
||||
//Разделение файлов
|
||||
if (consoleParser.HasParam("split"))
|
||||
FileSplit(consoleParser);
|
||||
|
||||
//Соединение файлов
|
||||
if (consoleParser.HasParam("join"))
|
||||
FileJoin(consoleParser);
|
||||
|
||||
//Функция разделения файлов
|
||||
static void FileSplit (ConsoleParamsParser @params)
|
||||
{
|
||||
//Публикую сообщение о работе с программой
|
||||
Console.WriteLine("Информация о работе с программой:\n\t" +
|
||||
"[c]rypt - шифровка архива\n\t" +
|
||||
"[d]ecrypt - дешифровка архива\n\t" +
|
||||
"[i]files - создание списка установочных файлов\n\t" +
|
||||
"[e]xit - Выход из программы\n\t[h]elp - Повторный вывод этого сообщения.");
|
||||
//Проверяю наличие параметров
|
||||
if (!@params.HasParam("-fn") || !@params.HasParam("-td") || !@params.HasParam("-ps"))
|
||||
{
|
||||
//- вывожу сообщение
|
||||
Console.WriteLine(Localization.MessageNoParametersForSplit);
|
||||
|
||||
//- прерываю
|
||||
return;
|
||||
}
|
||||
|
||||
//Получаю параметры
|
||||
//- имя исходного файла
|
||||
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 FileJoin (ConsoleParamsParser @params)
|
||||
{
|
||||
//Проверяю наличие параметров
|
||||
if (!@params.HasParam("-ifn") || !@params.HasParam("-tfn"))
|
||||
{
|
||||
//- вывожу сообщение
|
||||
Console.WriteLine(Localization.MessageNoParametersForSplit);
|
||||
|
||||
//- прерываю
|
||||
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>
|
||||
public class FileSplitInfo
|
||||
public sealed class FileSplitInfo
|
||||
{
|
||||
public FileSplitInfo()
|
||||
{
|
||||
SplitFiles = new();
|
||||
TargetFile = new TargetFileInfo();
|
||||
FileSplitterVersion = FileSplitterConstants.CurrentSplitterVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Версия программы, необходимая для сборки файла
|
||||
/// </summary>
|
||||
public string? FileSplitterVersion { get; set; }
|
||||
public string FileSplitterVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Информация о собираемом файле
|
||||
/// </summary>
|
||||
public ITargetFileInfo? TargetFile { get; set; }
|
||||
public TargetFileInfo TargetFile { get; set; }
|
||||
|
||||
/// <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>
|
||||
public class SplitFile: ISplitFile
|
||||
public sealed class SplitFile: ISplitFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Порядок части
|
||||
/// </summary>
|
||||
public byte Num { get; set; }
|
||||
public int Num { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Размер части
|
||||
|
@ -5,12 +5,21 @@ namespace FileSplitter.Shared.Classes;
|
||||
/// <summary>
|
||||
/// Информация о целевом файле
|
||||
/// </summary>
|
||||
public class TargetFileInfo: ITargetFileInfo
|
||||
public sealed class TargetFileInfo: ITargetFileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Конструктор
|
||||
/// </summary>
|
||||
internal TargetFileInfo()
|
||||
{
|
||||
FileName = string.Empty;
|
||||
FileHash = new byte[]{};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Имя файла
|
||||
/// </summary>
|
||||
public string? FileName { get; set; }
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Размер файла
|
||||
@ -20,10 +29,10 @@ public class TargetFileInfo: ITargetFileInfo
|
||||
/// <summary>
|
||||
/// md5-сумма файла для проверки
|
||||
/// </summary>
|
||||
public byte[]? FileHash { get; set; }
|
||||
public byte[] FileHash { get; set; }
|
||||
|
||||
/// <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>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ANBSoftware.ComponentsPack" Version="2023.409.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -8,7 +8,7 @@ public interface ISplitFile
|
||||
/// <summary>
|
||||
/// Порядок части
|
||||
/// </summary>
|
||||
public byte Num { get; set; }
|
||||
public int Num { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Размер части
|
||||
|
@ -8,7 +8,7 @@ public interface ITargetFileInfo
|
||||
/// <summary>
|
||||
/// Имя файла
|
||||
/// </summary>
|
||||
public string? FileName { get; set; }
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Размер файла
|
||||
@ -18,10 +18,10 @@ public interface ITargetFileInfo
|
||||
/// <summary>
|
||||
/// md5-сумма файла для проверки
|
||||
/// </summary>
|
||||
public byte[]? FileHash { get; set; }
|
||||
public byte[] FileHash { get; set; }
|
||||
|
||||
/// <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