Установка атрибутов файла
Получить информацию об атрибутах файла с помощью команд ОС можно, указав в свойстве Startlnfo.Arguments команду attrib и имя файла:
using System; using System.Diagnostics;
class MainClass {
public static void Main() {
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c attrib 104.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd(); Console.WriteLine("Output:");
Console.WriteLine(output); }
}

Полученная информация говорит о том, что файл 104.exe имеет атрибут А (архивный).
Если изменить свойство Startlnfo.Arguments на "/c attrib +S 104.exe", присвоим файлу ещё и атрибут S — 'системный':

При этом сам процесс присвоения никак не отражается в листинге: программа 105.exe в выходной поток ничего не направляет.
Получение структуры папки по команде tree
Из C#-программы можно получить структуру любой папки в виде дерева с помощью команды операционной системы tree. Воспользуемся для этого программой 106.cs.
//Программа 10 6.cs: Структура папки в виде дерева.
//Имя папки указать в командной строке при запуске программы.
using System;
using System.Diagnostics;
using System.IO;
class Class1 {
static void Main(string[] args) {
string dir = args[0]; Console.WriteLine("Исследуется папка " + dir + "\n");
ProcessStartInfo startinfo;
Process process = null;
string command, stdoutline;
StreamReader stdoutreader;
// Команда которую будет выполнять command = "tree ";
try
{
startinfo = new ProcessStartInfo();
// Запускаем через cmd startinfo.FileName = "cmd.exe";
// Ключ /c — выполнение команды
// Кроме команды можно вставить и необходимые параметры startinfo.Arguments = "/C " + command + dir;
// Не используем shellexecute startinfo.UseShellExecute = false;
// Перенаправить вывод на обычную консоль
startinfo.RedirectStandardOutput = true;
// Стартуем process = Process.Start(startinfo);
// Получаем вывод stdoutreader = process.StandardOutput;
while((stdoutline=stdoutreader.ReadLine())!= null)
{
// Выводим
Console.WriteLine(stdoutline);
}
stdoutreader.Close(); stdoutreader = null;
}
catch
{
throw;
}
finally
{
if (process != null)
{
// Закрываем process.Close();
}
// Освобождаем process = null; startinfo = null;
}
Console.ReadLine();
}
}

Вывод на экран текстового файла командой type
Если в программе 106.cs вместо команды tree вставить команду type, получим вывод на экран текста указанного в командной строке файла ():

Создание виртуального диска
Используем программу 108.cs и команду subst
Надо только иметь в виду, что команда type выводит текст в коде ASCII. Для вывода текста в другой кодировке необходимо программу вывода перестроить операционной системы для создания виртуального диска Q:.
//Программа 108.cs. Создание виртуального диска
using System;
using System.Diagnostics;
using System.IO;
class Class1
{
static void Main(string[] args) {
Console.WriteLine("Создаётся виртуальный диск " + "\n");
ProcessStartInfo startinfo; Process process = null;
string command, stdoutline;
StreamReader stdoutreader;
// Команда которую будет выполнять операционная система
command = "subst q: ";
try {
startinfo = new ProcessStartInfo();
// Запускаем через cmd startinfo.FileName = "cmd.exe";
// Ключ /c — выполнение команды
//Кроме команды можно вставить и необходимые параметры
// Задаём папку, в которой будет создан виртуальный диск
string dir = @"C:\Documents_and_Settings\All_Users";
startinfo.Arguments = "/C " + command + dir;
// Не используем shellexecute startinfo.UseShellExecute = false;
// Перенаправить вывод на обычную консоль
startinfo.RedirectStandardOutput = true;
// Стартуем process = Process.Start(startinfo);
// Получаем вывод stdoutreader = process.StandardOutput;
while((stdoutline=stdoutreader.ReadLine())!= null) {
// Выводим
Console.WriteLine(stdoutline);
}
stdoutreader.Close();
stdoutreader = null;
}
catch
{
throw;
}
finally
{
if (process != null)
{
// Закрываем process.Close();
}
// Освобождаем process = null; startinfo = null;
}
Console.ReadLine();
}
}

Проверка показывает, что в заданной папке создан виртуальный диск Q:.
Управление работой архиватора
Кроме программы WinRAR, имеющей оконный интерфейс, в комплект поставки архиватора входит файл Rar.exe. Это также 32-разрядная версия RAR для Windows, но она поддерживает только интерфейс командной строки и работает в текстовом (консольном) режиме. Консольную версию RAR удобно использовать для вызова из пакетных файлов (BAT и CMD), для запуска из приглашения DOS и т.п. Она поддерживает больше команд и ключей в командной строке, чем WinRAR.
Общий синтаксис командной строки для архивации файлов таков:
Rar.exe A [-ключи ] <Архив> [ Файлы ] [ @Файлы-списки ]
Например, если необходимо добавить файл copycat1.cs в архив LETTER.RAR, используется команда:
rar.exe a letter.rar copycatl.cs
Для сохранения в архиве файла используем программу 109.cs:
//109.cs: Управление архиватором из C#-программы
using System;
using System.Diagnostics;
using System.IO;
class Class1
{
static void Main(string[] args) {
ProcessStartInfo startinfo;
Process process = null;
string command;
// Команда которую будет выполнять command = " a ";
try {
string arhiv = "letter.rar"; string file = "copycat1.cs";
startinfo = new ProcessStartInfo();
// Запускаем архиватор startinfo.FileName = "rar.exe";
// Ключ /c — выполнение команды
// Кроме команды можно вставить и необходимые параметры
startinfo.Arguments = "/C " + command + " " + arhiv + " " + file;
// Не используем shellexecute startinfo.UseShellExecute = false;
// Стартуем process = Process.Start(startinfo); }
catch {
throw;
}
finally {
if (process != null) {
// Закрываем process.Close();
}
// Освобождаем process = null; startinfo = null;
}
Console.ReadLine();
}
}

При старте программы 109.exe запускается программа rar.exe и сообщает через консоль, что создаётся архив letter.rar и в него добавляется файл copycat1.cs. Операция выполнена успешно, о чём свидетельствуют OK Done.
Создание командного файла из С#-программы.
Создание текстового файла (bat или cmd)
Для того чтобы создать командный файл необходимо создать поток для записи в файл.
StreamWriter s = new StreamWriter("1.cmd", false);
где "1.cmd" — это имя создаваемого файла;
false — определяет, требуется ли добавить в файл данные.Если файл существует и значение этого параметра равно false, файл перезаписывается; если не существует, создается новый файл.
После создания потока необходимо записать в файл соответствующие команды. Запись в файл производится командами класса System.Console, такими, как Write() или WriteLine(). Например, создать директорий с именем "1" можно по команде операционной системы md 1. Перед командой надо указать имя созданного потока:
s.WriteLine("md 1");
Вывод на экран созданного файла
Выведем на экран содержимое нашего командного файла. Для этого создаем поток для чтения из файла и построчно выводим на экран его содержимое.
StreamReader r = new StreamReader("1.cmd");
while (!r.EndOfStream)
{
string str = r.ReadLine(); Console.WriteLine(str);
}
r.Close();
Здесь EndOfStream свойство класса StreamReader, определяющее, находится ли позиция текущего потока в конце потока. Пример.
В папке С:\Моно\222> размещаем файл 110.cs, в котором предусмотрено создание командного файла операционной системы, содержащего всего одну команду: "md 1", а затем — чтение этого файла с выводом его содержимого на экран.
//Файл 110.cs:
using System;
using System.IO;
public class Show
{
public static void Main() {
StreamWriter s = new StreamWriter("1.cmd",
false);
s.WriteLine("md 1"); s.Close();
StreamReader r = new StreamReader("1.cmd");
while (!r.EndOfStream)
{
string str = r.ReadLine(); Console.WriteLine(str);
}
r.Close();
Console.Read(); }
}
После компиляции получаем файл 110.exe, при исполнении которого на экран выводится созданная команда:

В папке с программой 110.cs появился файл 1.cmd:

Проблема длинных имён и возможные пути её решения
В операционной системе Windows разрешено использование «длинных имён» файлов и папок (каталогов или директориев). По данным MSDN полная длина имени файла не должна превышать 260 символов, а длина пути до файла или папки не должна быть выше 248 символов.
Однако во время работы каталоги формируются не сразу, а постепенно. Из них выстраивается иерархическая структура, в которой общая длина имени папок и файлов может значительно превысить установленные пределы, так как длины имён файлов и папок стандартными средствами операционной системы не контролируются.
Если длина адреса (пути к файлу) превышает допустимые пределы, представим полный путь к файлу (Р) состоящим из двух частей: р1 (допустимая длина пути) и р2 (запредельный путь).
Операционная система файл, находящийся по адресу Р из корня диска не видит. Поэтому ни одна команда операционной системы с этим файлом работать не сможет, если его попытаться достать из активного каталога, находящегося близко к корню диска.
Добраться до этого файла можно, если переместить активный каталог ОС на границу допустимого и запредельного пути. В этом случае путь к файлу нужно задавать относительно активного каталога, так как полный адрес к файлу распадётся на две части -р1 и р2:
C:\p1>copy p2
Допустимый путь р1 указывает операционной системе, откуда надо начинать выполнение команды, а тот адрес, который раньше был запредельным, становится допустимым.
Эта особенность работы с длинными именами стандартными средствами операционных систем Windows не учитывается. Поэтому часто можно встретиться с отказом работы с некоторыми папками Windows программами — архиваторами, программами для переноса информации на компакт-диски и DVD-диски, и др.
При копировании или перемещении такой папки надо либо использовать нестандартную программу копирования (перемещения), которая будет делить полный путь на два: допустимый — и запредельный, и переносить активный каталог на границу этих двух миров, либо надо корректировать структуру такого неправильного каталога.
Коррекция структуры выгоднее, так как позволит с исправленным каталогом работать стандартными средствами.
Коррекцию можно произвести по-разному. Рассмотрим два возможных метода: метод 1 — «сжатие имён»; метод 2 -архивирование «запредельной части» (и таким образом — сжатие полного имени).
Для первого метода можно применить один из известных алгоритмов сжатия (например — Лемпеля-Зива, DES, и др.). Но для работы полученные новые имена нужно как-то связывать со старыми…
Для второго метода структура информации практически не изменяется. Нужно только применить какой- нибудь архиватор.
При реализации 2 метода задача будет заключаться в следующем:
- Начать копирование (перемещение) заданной папки стандартным образом;
- При возникновении исключения из-за длины пути, выделить из полного пути допустимый путь и в конец его перенести активный каталог (в операционной системе это делается с помощью команды cd);
- Переместить каталог, вызвавший исключение, в корень диска. Операционная система это позволит сделать, так как запредельный ранее каталог теперь стал доступным;
- Архиватором сжать перемещённый каталог;
- Полученный архив переместить на место, которое занимал запредельный каталог;
- Продолжить операцию копирования (перемещения).
Результатом этого будет откорректированный каталог, в котором запредельно длинных имён не будет. Такой каталог можно скопировать или переместить стандартными средствами ОС, а если нужно сохранить прежнюю структуру каталога, архив можно сделать саморазворачивающимся (SFX) и развернуть его после копирования на новое место.
Для ускорения работы архиватор можно использовать стандартный, например, RAR.
В данном случае решение задачи достигается за счёт комплексирования программных средств: С#-программы копирования (перемещения) каталогов, операторов ОС и посторонней программы архивации.
Проверка наличия в папке имён, длиной более 200 символов
При запуске программы в командной строке после имени запускаемой программы указывается имя исследуемой папки. Например, имя программы 114.exe, исследуется папка С:\Моно\Результат. Текст программы 114.cs:
//Программа 114.cs. Фиксация папок с длиной имени более 200 символов:
using System;
using System.IO;
class Class1 {
//Точка входа в программу [STAThread]
static void Main(string[] args) {
string dir = args[0]; analiz(dir);
}
static void analiz(string dir) //Анализ длины имён
{
Console.WriteLine("Исследуется папка " + dir + "\n");
string [] subdirectory =
Directory.GetDirectories(dir,"*",System.IO.SearchOption.AllD irectories);
Console.WriteLine("Количество подкаталогов в папке " + subdirectory.Length);
int k=0;
for (int i = 0; i < subdirectory.Length; i++)
{
if(subdirectory[i].Length > 200)
{
Console.WriteLine(i + " " + subdirectory[i] + " " + subdirectory[i].Length); k+ = 1;
}
}
if(k==0)
{
Console.WriteLine("Папок с длиной имени более 200 символов нет ");
}
}
}
При отсутствии длинных имён:

А при наличии длинных имён выводятся порядковый номер каталога, путь к нему и длина имени:

Программа коррекции неправильных каталогов (со сверхдлинными путями)
Коррекция каталогов со сверхдлинными именами предусматривает:
- Создание в корне какого-либо диска рабочего каталога с именем "v";
- Размещение в этом каталоге необходимых для работы файлов: основного файла -архиватора rar.exe, вспомогательного файла архиватора — default.sfx, командного файла для запуска архиватора — comand.cmd;
- При моделировании реконструкции каталога требуется дополнительное мероприятие: создание каталога требуемой конструкции. Такой каталог может быть создан по адресу: с:\^Эксперимент\3. Этот каталог должен содержать иерархическую структуру подкаталогов с требуемой длиной и конструкцией имён;
- Программа remont.cs выполняет следующие действия:
- получает структуру каталогов исследуемой папки;
- перемещает каталог subdir (subdir — это переменная, содержащая текущее значение имени), длина имени которого превышает заданную величину, в рабочий каталог v и изменяет его имя на 1;
- запускает файл command.cmd, преобразующий каталог в sfx-архив (файл);
- перемещает созданный sfx-архив на место каталога subdir и изменяет его имя на subdir.exe.
Если каталог subdir имел в свою очередь иерархическую структуру, она обрывается, и таким образом сокращается общая длина имени.
//Текст программы Remont2.cs
using System;
using System.IO;
using System.Diagnostics;
namespace RemontDir
{
class RemDir {
static void Main(string[] args)
{
string rab = @"c:\v\1";
string dir = @"С:\у\Эксперимент\3";
string [] subdirectory = Directory.GetDirectories(dir,"*", System.IO.SearchOption.AllDirectories);
foreach (string subdir in subdirectory)
{
if (subdir.Length > 200) {
Console. WriteLine("\n" + subdir + " " + subdir.Length);
Directory.Move(subdir, rab); //Console.Read();
Process. Start(Vomand.cmd");
Directory.Move(@"c:\v\l.exe", subdir); //Console.Read();
}
}
}
}
}
Работа этой программы в автоматическом режиме на экране не отображается. Добавим в программу отладочные операторы, останавливающие её в контрольных точках. После остановки средствами операционной системы проанализируем состояние необходимых файлов и каталогов.
Фрагмент содержания папки c:\v перед началом работы программы remont2.exe:

Текст командного файла comand.cmd.

Результат анализа исследуемой папки программой 114.exe перед началом работы программы remont2.exe:

Структура исследуемой папки, полученная перед ремонтом по команде tree операционной системы:

Исполнение командного файла comand.cmd:

Содержимое диска v после работы архиватора:

Из рисунка видно, что на диске добавились папка "1" и sfx-архив 1.exe.
Проверка исследуемого каталога после преобразования по программе 114.exe:

Общее количество каталогов в папке уменьшилось, так как каталоги 10-14 являются подкаталогами каталога 9, имеющего размер имени больше 200 символов. Все они включены в архив 1.exe, что видно из протокола работы командного файла.