Аватар для Orlov1
100 / 42 / 7
Регистрация: 03.02.2019
Сообщений: 657

Распаковка архивов

29.05.2025, 23:46. Показов 2756. Ответов 23

Студворк — интернет-сервис помощи студентам
Есть код, который распаковывает архивы, находящиеся в директории, используя стандартные средства Winrar и консольную команду. Подскажите как записать в коде обработку вложенных архивов, т.е если распаковали архив и в архиве еще один архив, то его распаковать с сохранением структуры каталогов.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
 
class ArchiveExtractor
{
    static void Main()
    {       
        string archivesPath = ("d:\\1\\");
 
        string outputPath = PrepareOutputDirectory();
                       
        string[] archiveFiles = Directory.GetFiles(archivesPath, "*.7z")
            .Concat(Directory.GetFiles(archivesPath, "*.zip"))
            .Concat(Directory.GetFiles(archivesPath, "*.rar"))
            .ToArray();
 
        foreach (string archivePath in archiveFiles)
        {
            ProcessArchive(archivePath, outputPath);
        }
                
        Console.ReadKey();
    }
 
    private static string PrepareOutputDirectory()
    {
        string outputPath = Path.Combine(Directory.GetCurrentDirectory(), "output");
        if (!Directory.Exists(outputPath))
            Directory.CreateDirectory(outputPath);
 
        return outputPath;
    }
    
    private static void ProcessArchive(string archivePath, string baseOutputPath)
    {
        string archiveName = Path.GetFileName(archivePath);
        Console.WriteLine($"Распаковка архива {archiveName}...");
 
        try
        {
           
            string archiveFolderName = Path.GetFileNameWithoutExtension(archivePath);
            string outputPath = Path.Combine(baseOutputPath, archiveFolderName);
 
            ExtractWithWinRAR(archivePath, outputPath);
 
            Console.WriteLine($"Распаковка архива {archiveName} завершена успешно.");
            
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при распаковке архива {archiveName}: {ex.Message}");
        }
    }
    
    private static void ExtractWithWinRAR(string archivePath, string outputPath)
    {
        string winRarPath = GetWinRarPath();
        if (winRarPath == null)
            throw new FileNotFoundException("WinRAR не найден!");
 
        Directory.CreateDirectory(outputPath);
                
        string args = $"x -ibck -y -r -o+ \"{archivePath}\" \"{outputPath}\"";
        using (Process process = new Process())
        
        {
            process.StartInfo = new ProcessStartInfo
            {
                FileName = winRarPath,
                Arguments = args,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardError = true
            };
 
            process.Start();
            process.WaitForExit();
 
            if (process.ExitCode != 0)
                throw new Exception("Ошибка при распаковке архива.");
        }
 
    }
    private static string GetWinRarPath()
    {
        string[] possiblePaths =
        {
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "Rar.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "Rar.exe")
        };
 
        return possiblePaths.FirstOrDefault(File.Exists);
    }
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
29.05.2025, 23:46
Ответы с готовыми решениями:

Распаковка архивов, в том числе и запароленных
Как распаковать запороленный архив WinRar или Zip, ну или хотя бы просто распаковать архив?

Распаковка rar-архивов
Перепрбывал много чего и в том числе сторонние библиотеки, вот код, надо расспаковать два архива....

Распаковка архивов в отдельные папки
имеется архив 123.rar, в нем находятся еще 3 архива 1.rar, 2.rar и 3.rar. Необходимо распаковать...

23
118 / 19 / 7
Регистрация: 27.05.2025
Сообщений: 72
30.05.2025, 00:55
Распаковывать архив в папку с именем архива, проверять там наличие архивов и повторять распаковку рекурсивно до тех пор пока архивы перестанут определяться.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
30.05.2025, 01:20
Создать метод ProcessDurectory и выносим в нее код касающийся поиска архивов и запуска их на распаковку.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    static void Main()
    {       
        string archivesPath = ("d:\\1\\");
        // запускаем обработку директории
        ProcessDirectory(archivesPath);
        Console.ReadKey();
    }
 
   private static void ProcessDirectory(string archivesPath){
      string outputPath = PrepareOutputDirectory();
                    
      string[] archiveFiles = Directory.GetFiles(archivesPath, "*.7z")
         .Concat(Directory.GetFiles(archivesPath, "*.zip"))
         .Concat(Directory.GetFiles(archivesPath, "*.rar"))
         .ToArray();
      
      foreach (string archivePath in archiveFiles)
      {
         ProcessArchive(archivePath, outputPath);
      }
   }
В ProcessArchive добавляем строчку обработки только что созданной директории после распаковки.
C#
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
        try
        {
           
            string archiveFolderName = Path.GetFileNameWithoutExtension(archivePath);
            string outputPath = Path.Combine(baseOutputPath, archiveFolderName);
 
            ExtractWithWinRAR(archivePath, outputPath);
 
            // рекурсивно обрабатываем распакованную директорию
            ProcessDirectory(outputPath);
            // ----
 
            Console.WriteLine($"Распаковка архива {archiveName} завершена успешно.");
            
        }
В теории. С минимальными правками. Не тестировал.

Всё это можно сделать и без рекурсии. Но правок понадобится намного больше.
1
 Аватар для qwerty.123
19 / 18 / 1
Регистрация: 25.05.2025
Сообщений: 39
30.05.2025, 14:40
C#
1
string outputPath = Path.Combine(Directory.GetCurrentDirectory(), "output");
Это можно записать компактней:
C#
1
string outputPath = $".{Path.DirectorySeparatorChar}output";
C#
1
2
if (!Directory.Exists(outputPath))
Directory.CreateDirectory(outputPath);
В данном случае нет смысла проверять каталог на существовании. Если каталога нет, то он будет создан. Если он уже существует, то ничего не произойдёт (т.е. никакого исключения не произойдёт).

А вообще, конечно же, в методе PrepareOutputDirectory() нет никакой необходимости.

C#
1
Console.WriteLine($"Ошибка при распаковке архива {archiveName}: {ex.Message}");
Привыкайте писать ошибки в правильный поток:

C#
1
Console.Error.WriteLine($"Ошибка при распаковке архива {archiveName}: {ex.Message}");
Кроме того, подход к решению, в целом, неправильный: а если на компьютере нет WinRar? Ведь далеко не у всех он есть: например, у меня его нет (использую 7Zip). А если приложение установлено portable в каталоге отличном от тех, в которых вы ищете exe-файл? А если это Linux или Mac? Не надо искать .exe-файлы. Вместо этого нужно подключить нужные NuGet-пакеты и использовать их. Лучше сразу привыкать писать кроссплатформенный код, если есть такая возможность (в данном случае она есть).

Возьмите за правило всегда первым делом валидировать параметры, полученные при вызове вашего метода. Например, проверяйте на то, что вам не передали пустые строки или null там, где они не должны появиться.

Если в вашем архиве есть несколько вложенных архивов, каждый из которых вы хотите распаковывать в отдельный подкаталог, то делайте это одновременно в параллельных потоках (у вас же не один одноядерный процессор на компьютере).
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,234
30.05.2025, 16:25
Цитата Сообщение от Orlov1 Посмотреть сообщение
Подскажите как записать в коде обработку вложенных архивов, т.е если распаковали архив и в архиве еще один архив, то его распаковать с сохранением структуры каталогов.
Можно как в DFS-е (поиск в глубину), обрабатывать архивы по одному на основе стека:
- Ложим все тарболы на стек, начинаем обрабатывать по одному
- После обработки каждого архива, проверяем его outputDir - создаем на его основе еще пачку задач на обработку, уже с новым baseOutputPath.

Вот так выглядит main после рефакторинга:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void Main()
    {       
        string archivesPath = ("d:\\1\\");
 
        var stack = new Stack<ProcessItem>();
        foreach (var archive in EnumerateArchives(archivesPath))
            stack.Push(new ProcessItem(archive));
        
        while (stack.Count > 0)
        {
            var item = stack.Pop();
            ProcessArchive(item);
 
            var outputDir = GetOutputDir(item);
            foreach (var archive in EnumerateArchives(outputDir))
                stack.Push(new ProcessItem(archive, outputDir));
        }
        
                
        Console.WriteLine("Process completed");
    }
Полный код

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System.Diagnostics;
 
class ArchiveExtractor
{
    private static readonly string BASE_OUTPUT_PATH = PrepareOutputDirectory();
    
    static void Main()
    {       
        string archivesPath = ("d:\\1\\");
 
        var stack = new Stack<ProcessItem>();
        foreach (var archieve in EnumerateArchieves(archivesPath))
            stack.Push(new ProcessItem(archieve));
        
        while (stack.Count > 0)
        {
            var item = stack.Pop();
            ProcessArchive(item);
 
            var outputDir = GetOutputDir(item);
            foreach (var tarball in EnumerateArchieves(outputDir))
                stack.Push(new ProcessItem(tarball, outputDir));
        }
        
                
        Console.WriteLine("Process completed");
    }
 
    private static string PrepareOutputDirectory()
    {
        string outputPath = Path.Combine(Directory.GetCurrentDirectory(), "output");
        if (!Directory.Exists(outputPath))
            Directory.CreateDirectory(outputPath);
 
        return outputPath;
    }
    
    private static void ProcessArchive(ProcessItem item)
    {
        string archiveName = Path.GetFileName(item.archievePath);
        Console.WriteLine($"Распаковка архива {archiveName}...");
 
        try
        {
            string outputPath = GetOutputDir(item);
            ExtractWithWinRAR(item.archievePath, outputPath);
 
            Console.WriteLine($"Распаковка архива {archiveName} завершена успешно.");
            
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при распаковке архива {archiveName}: {ex.Message}");
        }
    }
    
    private static void ExtractWithWinRAR(string archivePath, string outputPath)
    {
        string winRarPath = GetWinRarPath();
        if (winRarPath == null)
            throw new FileNotFoundException("WinRAR не найден!");
 
        Directory.CreateDirectory(outputPath);
                
        string args = $"x -ibck -y -r -o+ \"{archivePath}\" \"{outputPath}\"";
        using (Process process = new Process())
        
        {
            process.StartInfo = new ProcessStartInfo
            {
                FileName = winRarPath,
                Arguments = args,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardError = true
            };
 
            process.Start();
            process.WaitForExit();
 
            if (process.ExitCode != 0)
                throw new Exception("Ошибка при распаковке архива.");
        }
 
    }
    private static string GetWinRarPath()
    {
        string[] possiblePaths =
        {
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "Rar.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "Rar.exe")
        };
 
        return possiblePaths.FirstOrDefault(File.Exists);
    }
 
    private static string GetOutputDir(ProcessItem item)
    {
        string archiveFolderName = Path.GetFileNameWithoutExtension(item.archievePath);
        return Path.Combine(item.baseOutputPath ?? BASE_OUTPUT_PATH, archiveFolderName);
    }
 
    private static IEnumerable<String> EnumerateArchives(String path)
    {
        return Directory.GetFiles(path, "*.7z")
            .Concat(Directory.GetFiles(path, "*.zip"))
            .Concat(Directory.GetFiles(path, "*.rar"))
    }
}
 
 
struct ProcessItem(string archievePath, string? baseOutputPath = null)
{
    internal String archievePath = archievePath; 
    
    internal String? baseOutputPath = baseOutputPath;
}


Добавлено через 28 секунд
Не тестировал, на лине сижу - тут WinRar-ов нету.

Добавлено через 15 минут
Немного еще рефакторинга (ProcessItem is immutable):
C#
1
2
3
4
5
6
readonly struct ProcessItem(string archievePath, string? baseOutputPath = null)
{
    internal readonly String archievePath = archievePath; 
    
    internal readonly String? baseOutputPath = baseOutputPath;
}
Добавлено через 3 минуты
Можно развить тему и передавать директорию через параметры приложения.

Добавлено через 8 минут
Orlov1, по поводу Directory.GetCurrentDirectory() - тут надо задать себе вопрос.
Задумка была действительно использовать текущую директорию или все-таки должна использоваться директория в которой лежит бинарь?
Потому что в общем случае это разные вещи.
2
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
30.05.2025, 17:38
qwerty.123, #4 - план-"пятилетка" для начинающего

Добавлено через 1 минуту
p.s.:
Цитата Сообщение от qwerty.123 Посмотреть сообщение
Возьмите за правило всегда первым делом валидировать параметры
Я бы добавил: "в клиентском коде".
Не везде это нужно. Иначе получится "проверка проверкой погоняет".
0
 Аватар для qwerty.123
19 / 18 / 1
Регистрация: 25.05.2025
Сообщений: 39
30.05.2025, 17:50
Цитата Сообщение от SmallEvil
Не везде это нужно. Иначе получится "проверка проверкой погоняет".
Код метода не должен полагаться на то, что проверка параметров была выполнена в вызывающем этот метод коде. Во первых, такую проверку писать перед каждым вызовом метода будет утомительно. Во вторых, где-то могут сделать оЧепятку и проверка будет не совсем верной. В третьих, её вообще могут не делать.

Поэтому никогда не стоит полагаться на то, что полученные методом параметры уже были проверены извне. Ну и кроме того, всегда проще поправить логику проверки параметров в одном месте (в коде метода), чем везде, где этот метод вызывается (например в случае, если у метода была изменена сигнатура).

Соответственно, проверка параметров должна выполняться в одном месте - в коде самого метода (причём в самом начале). Например:

C#
1
2
3
4
5
static Task ExtractAsync(string zippedFileName, string targetDirectory, CancellationToken cancellationToken = default)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(zippedFileName, nameof(zippedFileName));
        ArgumentException.ThrowIfNullOrWhiteSpace(targetDirectory, nameof(targetDirectory));
...
Кстати, о необходимости проверки параметров в коде самого метода (если вы не пишете что-то низкоуровневое, системное, скрытое от внешнего использования) пишет в т.ч. и Беарне Стровструп (создатель языка C++) в своей книге "Практика программирования на C++".
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
30.05.2025, 18:01
Цитата Сообщение от qwerty.123 Посмотреть сообщение
Код метода не должен полагаться на то, что проверка параметров была выполнена в вызывающем этот метод коде. Во первых, такую проверку писать перед каждым вызовом метода будет утомительно. Во вторых, где-то могут сделать оЧепятку и проверка будет не совсем верной. В третьих, её вообще могут не делать.
Это всё проблемы индейцев.
Есть контракты. Им нужно следовать. Всё просто.
Если контракт оглашает что данные должны быть строго такими-то, то это проблема вызывающего кода предоставить их.
Каким образом это будет осуществлено, это дело 100500-е.
имхо. наверное мы друг друга не поняли.

И ли это действительно Шарписты так пишут. 100500 проверок, а контракты зачем?
0
 Аватар для qwerty.123
19 / 18 / 1
Регистрация: 25.05.2025
Сообщений: 39
30.05.2025, 18:13
Цитата Сообщение от SmallEvil
И ли это действительно Шарписты так пишут. 100500 проверок, а контракты зачем?
Вот как раз чтобы не делать 100500 проверок, проверка параметров должна выполняться в коде метода, которому эти параметры переданы.

А ежели эти параметры передаются сквозным образом (от метода к методу), то ничего страшного в том, что каждый из них выполнит проверку.

Лучше проверить параметры несколько раз и выявить ошибку, чем не проверить их, выполнить часть бизнес-логики и потом вдруг обнаружить, что один из полученных параметров "кривой".

В нашей команде мы не пропускаем pull request, если в методе не выполняется проверка полученных параметров. Если вы работаете иначе - это ваше право.

Цитата Сообщение от SmallEvil
Есть контракты. Им нужно следовать. Всё просто.
Я не понимаю, о каких контрактах вы говорите. Под словом "контракт" я всегда подразумеваю программные интерфейсы (interface), перечисления (enums), абстрактные классы и делегаты. Т.е. абстрагирование от конкретных реализаций.
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,234
30.05.2025, 18:50
Цитата Сообщение от SmallEvil Посмотреть сообщение
Есть контракты.
А есть враждебный для публичных методов клиентский код, который может подсунуть все что угодно.
"Принцип самурая" никто не отменял.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
30.05.2025, 18:51

Не по теме:

Цитата Сообщение от qwerty.123 Посмотреть сообщение
Я не понимаю, о каких контрактах вы говорите.
На данный момент, я говорю немного абстрактно, о части более общего подхода(design by contract).
А именно : Контрактное программирование: предусловие
На англ. статья нагляднее
Design by contract

Но как бы это уже в оффтоп зашло.



Добавлено через 39 секунд
Цитата Сообщение от IamRain Посмотреть сообщение
А есть враждебный для публичных методов клиентский код, который может подсунуть все что угодно.
Это можно сделать в любом случае.
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,234
30.05.2025, 18:53
Цитата Сообщение от SmallEvil Посмотреть сообщение
а контракты зачем?
Вы что-то путаете. Как раз чтобы контракт соблюдался, нужно и валидировать параметры, контракт нарушен - делаем сэппуку.
0
30.05.2025, 18:54

Не по теме:

Цитата Сообщение от IamRain Посмотреть сообщение
Вы что-то путаете.
Шарписты это особый народец. )
Лады.
Ухожу в закат.

0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,234
30.05.2025, 18:56
Цитата Сообщение от SmallEvil Посмотреть сообщение
Это можно сделать в любом случае.
Что значит эта фраза?

Добавлено через 1 минуту

Не по теме:


Цитата Сообщение от SmallEvil Посмотреть сообщение
Шарписты это особый народец. )
У нас все формализовано, мало хаоса - это все идет на законодательном уровне (шучу, от Microsoft). А вы вносите хаос. :)

0
30.05.2025, 19:32

Не по теме:

Цитата Сообщение от IamRain Посмотреть сообщение
А вы вносите хаос. :)
Тут и без меня хорошо справляются)

0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,234
30.05.2025, 19:57
Orlov1, пожалуй, еще немного рефакторинга - сделал GetOutputDir экземплярным методом ProcessItem:

Main:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void Main()
    {       
        string archivesPath = ("d:\\1\\");
 
        var stack = new Stack<ProcessItem>();
        foreach (var archive in EnumerateArchives(archivesPath))
            stack.Push(new ProcessItem(archive));
        
        while (stack.Count > 0)
        {
            var item = stack.Pop();
            ProcessArchive(item);
 
            var outputDir = item.GetOutputDir();
            foreach (var archive in EnumerateArchives(outputDir))
                stack.Push(new ProcessItem(archive, outputDir));
        }
        
                
        Console.WriteLine("Process completed");
    }
Полный код

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using System.Diagnostics;
 
class ArchiveExtractor
{
    internal static readonly string BASE_OUTPUT_PATH = PrepareOutputDirectory();
    
    static void Main()
    {       
        string archivesPath = ("d:\\1\\");
 
        var stack = new Stack<ProcessItem>();
        foreach (var archive in EnumerateArchives(archivesPath))
            stack.Push(new ProcessItem(archive));
        
        while (stack.Count > 0)
        {
            var item = stack.Pop();
            ProcessArchive(item);
 
            var outputDir = item.GetOutputDir();
            foreach (var archive in EnumerateArchives(outputDir))
                stack.Push(new ProcessItem(archive, outputDir));
        }
        
                
        Console.WriteLine("Process completed");
    }
 
    private static string PrepareOutputDirectory()
    {
        string outputPath = Path.Combine(Directory.GetCurrentDirectory(), "output");
        if (!Directory.Exists(outputPath))
            Directory.CreateDirectory(outputPath);
 
        return outputPath;
    }
    
    private static void ProcessArchive(ProcessItem item)
    {
        string archiveName = Path.GetFileName(item.archivePath);
        Console.WriteLine($"Распаковка архива {archiveName}...");
 
        try
        {
            ExtractWithWinRAR(item.archivePath, item.GetOutputDir());
            Console.WriteLine($"Распаковка архива {archiveName} завершена успешно.");
            
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Ошибка при распаковке архива {archiveName}: {ex.Message}");
        }
    }
    
    private static void ExtractWithWinRAR(string archivePath, string outputPath)
    {
        string winRarPath = GetWinRarPath();
        if (winRarPath == null)
            throw new FileNotFoundException("WinRAR не найден!");
 
        Directory.CreateDirectory(outputPath);
                
        string args = $"x -ibck -y -r -o+ \"{archivePath}\" \"{outputPath}\"";
        using (Process process = new Process())
        
        {
            process.StartInfo = new ProcessStartInfo
            {
                FileName = winRarPath,
                Arguments = args,
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardError = true
            };
 
            process.Start();
            process.WaitForExit();
 
            if (process.ExitCode != 0)
                throw new Exception("Ошибка при распаковке архива.");
        }
 
    }
    private static string GetWinRarPath()
    {
        string[] possiblePaths =
        {
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "WinRAR.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WinRAR", "Rar.exe"),
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "WinRAR", "Rar.exe")
        };
 
        return possiblePaths.FirstOrDefault(File.Exists);
    }
    
    private static IEnumerable<String> EnumerateArchives(String path)
    {
        return Directory.GetFiles(path, "*.7z")
            .Concat(Directory.GetFiles(path, "*.zip"))
            .Concat(Directory.GetFiles(path, "*.rar"));
    }
}
 
 
readonly struct ProcessItem(string archivePath, string? baseOutputPath = null)
{
    internal readonly String archivePath = archivePath;
 
    private readonly String? baseOutputPath = baseOutputPath;
 
    internal string GetOutputDir() =>
        Path.Combine(baseOutputPath ?? ArchiveExtractor.BASE_OUTPUT_PATH,
            Path.GetFileNameWithoutExtension(archivePath));
}
0
30.05.2025, 21:15

Не по теме:

Цитата Сообщение от qwerty.123 Посмотреть сообщение
Возьмите за правило всегда первым делом валидировать параметры, полученные при вызове вашего метода.
Цитата Сообщение от qwerty.123 Посмотреть сообщение
Поэтому никогда не стоит полагаться на то, что полученные методом параметры уже были проверены извне.
Эти два слова стоит употреблять в крайне исключительных ситуациях, и хорошо обдумать нужны ли они там.
Я лишь написал, что не согласен именно в категоричности ваших суждений.

0
 Аватар для qwerty.123
19 / 18 / 1
Регистрация: 25.05.2025
Сообщений: 39
30.05.2025, 21:43
Цитата Сообщение от SmallEvil
Эти два слова стоит употреблять в крайне исключительных ситуациях, и хорошо обдумать нужны ли они там.
Я лишь написал, что не согласен именно в категоричности ваших суждений.
Я так же писал следующее:
(если вы не пишете что-то низкоуровневое, системное, скрытое от внешнего использования)
Поскольку на C# пишут не ядро операционной системы, то я сознательно употребил эти слова.

Тема превратилась в холивар. Я более не буду писать в ней.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
30.05.2025, 22:17
Цитата Сообщение от qwerty.123 Посмотреть сообщение
Тема превратилась в холивар.
Конечно, безумное однобокое видение, приводящее к диким тормозам, легко приводят к холиварам и к Юнити и играм на них.
С геймплеем и графикой как у ДОС игр но с требованием современных игровых ПК.
0
31.05.2025, 08:44

Не по теме:

Тема превратилась в холивар. Я более не буду писать в ней.
Можно попросить модераторов вынести дискусию в отдельную тему, раз зацепились.

По "холивару": пишем, когда имеет смысл.

вариант 1: передаваемый параметр задействуется где-то там, а перед ним куча кода, который не очень хочется запускать в пустую.

вариант 2: это метод либы, и желательно чтобы выше отлавливалось не NRE внутренностей, а более осознанное исключение. Тут больше вопрос удобства работы с кодом и его сопровождением: найти в логах "ArgumentException parameter fileName" гораздо приятней чем просто NullReferenceException line 17.

Лепить такие проверки на каждый чих действительно не очень. Как вариант можно воспользоваться фичей "nullable reference" (хотя по ней тоже ведутся споры), тем самым контракт будет более явный когда можно, а когда нельзя передавать null. В этом случае компилятор подскажет, где следует выполнить проверки, а где избыточны.

Подход "ничего не знаю, вызывающая сторона должна валидировать данные" тоже имеет смысл, особенно когда остро стоит вопрос перфоманса. Тем не менее если вы копнёте те же исходники C#, там очень много таких проверок.

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.05.2025, 08:44
Помогаю со студенческими работами здесь

Распаковка архивов
Пишу программу на c#. Она у меня распознает документы ворд и записывает их в таблицу. Теперь нужно...

Запуск архивов по очереди
Здравствуйте бьюсь над следующей проблемой на форме есть progressBar1 который должен менять свое...

Склеивание архивов GZipStream - Неверный размер файла
Всем привет. Пишу архиватор, который делит исходный файл на фрагменты, их жмёт GZipStream, далее...

Параллельное создание zip архивов на WEB странице останавливается
Не веб-сайте есть страничка &quot;Создать архивы&quot;. Жму кнопку, создаются пустые архивы и начинается...

Подвисания при распаковке архивов из ресурсов
Приветствую! Разрабатываю свой WPF, в ресурсах лежит большое количество тяжеловесных zip архивов....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

Новые блоги и статьи
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
Отчёт о затраченных материалах за определенный период с макетом печатной формы
Maks 21.04.2026
Отчёт из решения ниже размещён в конфигурации КА2. Задача: разработка отчёта по затраченным материалам за определённый период, с возможностью вывода печатной формы отчёта с шапкой и подвалом. В. . .
Отчёт о спецтехнике находящейся в ремонте
Maks 20.04.2026
Отчёт из решения ниже размещен в конфигурации КА2. Задача: отобразить спецтехнику, которая на данный момент находится в ремонте. Есть нетиповой документ "Заявка на ремонт спецтехники" который. . .
Памятка для бота и "визитка" для читателей "Semantic Universe Layer (Слой семантической вселенной)"
Hrethgir 19.04.2026
Сгенерировано для краткого описания по случаю сборки и компиляции скелета серверного приложения. И пусть после этого скажут, что статьи сгенерированные AI - туфта и не интересно. И это не реклама -. . .
Запрет удаления строк ТЧ документа при определённом условии
Maks 19.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "Аккумуляторы", разработанного в конфигурации КА2. У данного документа есть ТЧ, в которой в зависимости от прав доступа. . .
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru