1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 88
Текст из файла (страница 88)
//Работас коллекциями// номером строкиConsole.Write("{0:D3} - ", n L i n e ) ;DumpBuffer(buffer, numBytes),// После каждых 2 0 строк останавливаемся, так как// прокрутка консольного окна отсутствуетif ((nLine % 20) == 0){Console.WriteLine("Нажмите <Enter> для вывода " +"очередных 20 с т р о к " ) ;Console.ReadLine();}}// DumpBuffer - вывод буфера символов в виде единой// строки в шестнадцатеричном форматеpublic static void DumpBuffer(byte[] buffer,int numBytes)for(int index = 0;index < numBytes;index++)byte b = buffer[index] ,•Console.Write("{0:X2}, ", b) ,Console.WriteLine();}}}В командной строке пользователь указывает каталог, применяемый в качестве aprylмента программы. Приведенная далее команда выведет шестнадцатеричный дамп каждо- [го файла из временного каталога (как текстовых, так и бинарных файлов):loopthroughfilesc:\randy\tempЕсли не ввести имя файла, программа по умолчанию использует текущий каталог.!(Шестнадцатеричный дамп выводит все числа в шестнадцатеричной системе счисле-jния — см.
врезку "Шестнадцатеричные числа".)Шестнадцатеричные числаКак и бинарные числа (0 и 1), шестнадцатеричные числа также очень важны в компьютерном программировании. В шестнадцатеричной системе счисления цифрами являются обычные десятичные цифры 0-9 и буквы А, В, С, D, Е, F — где А = 10, В = 11,F = 15. Для иллюстрации (префикс Ох указывает на шестнадцатеричность выводимого числа): OxD = 13. 0x10 = 16: 1*16 + 0 * 1 . 0х2А = 42: 2*16 + А*1 (здесь А*1 =10*1). Буквы могут быть как строчными, так и прописными: F означает то же, что ит.Эти числа выглядят причудливо, но они очень полезны, в особенности при отладкеили работе с аппаратной частью или содержимым памяти.Демонстрационные программы FileRead и FileWrite считывали именафайлов с консоли, в то время как в этой программе имя файла передается в командной строке.
Поверьте, вас никто не пытается запутать, а всего лишь предлагаются различные варианты решения одной и той же задачи.448Часть VII. Дополнительные главыПервая строкаличие аргумента ввен 0), программазапущена из Visualваться подкаталогдемонстрационной программы LoopThroughFiles определяет накомандной строке. Если список аргументов пуст (args.
Length равызывает Directory. GetCurrentDirectory ( ) . Если программаStudio, а не из командной строки, то по умолчанию будет использоbin\Debug в каталоге проекта LoopThroughFiles.Класс Directory предоставляет пользователю набор методов для работыс каталогами, а класс Filelnf о— методы для перемещения, копированияи удаления файлов.Затем программа получает список всех файлов в указанном каталоге посредством вызова GetFileList ( ) . Эта функция возвращает массив объектов Filelnf о.
Каждыйобъект Filelnf о содержит информацию о ф а й л е — например, имя файла (как полноеимя с путем, FullName, так и без пути — Name), дату его создания и время последнегоизменения. Функция Main () проходит по всему списку файлов с помощью циклаforeach.
Она выводит имя каждого файла и передает его функции DumpHex () для вывода содержимого на консоль.Пауза в конце каждого цикла позволяет программисту просмотреть выведеннуюDumpHex () информацию.Функция GetFileList () начинает работу с создания пустого списка Filelnf о,который будет возвращен в случае ошибки.Этот прием стоит запомнить и использовать при работе с функциями Get...List ():если происходит ошибка, вывести сообщение о ней и вернуть пустой список.Будьте внимательны при возврате ссылок. Например, не возвращайте ссылкини на одну из внутренних очередей в классе PriorityQueue в главе 15,"Обобщенное программирование", если не хотите намеренно пригласить пользователей мешать нормальной работе класса (работой не посредством методовкласса, а напрямую с очередями). Но GetFileList (} не дает вам доступак внутренностям одного из ваших классов, так что в данном случае все в порядке.Затем функция GetFileList () создает объект Directorylnf о.
Как и гласит егоимя, объект Directorylnf о содержит тот же вид информации о каталоге, что и объектFilelnf о о файле. Однако у объекта Directorylnf о есть доступ к одной вещи, к которой нет доступа у объекта Filelnf о, а именно к списку файлов каталога в виде массива Filelnfо.Как обычно, функция GetFileList () помещает код, работающий с файлами и каталогами, в большой try-блок. Конструкция catch в конце функции перехватывает всегенерируемые ошибки и выводит имя каталога (которое, вероятно, введено неверно, т.е.такого каталога не существует).Функция DumpHex () несколько сложнее из-за трудностей в форматировании вывода.Функция DumpHex () начинает работу с открытия файла.
Объект Filelnf о содержит информацию о файле, но не открывает его. Функция DumpHex () получает полноеимя файла, включая путь. Затем она открывает FileStream в режиме только для чтения с использованием этого имени. Блок catch перехватывает исключение, еслиFileStream не в состоянии прочесть файл по той или иной причине.Затем DumpHex () считывает файл по 10 байт за раз и выводит их в одну строку вшестнадцатеричном формате. После вывода каждых 20 строк программа приостанавливает работу в ожидании нажатия пользователем клавиши <Enter>.Глава 20. Работа с коллекциями449По вертикали консольное окно по умолчанию имеет 25 строк (правда, пользователь может изменить эту настройку, добавив или убрав строки).
Это означает, что вы должны делать паузу после вывода каждых 20 строк или около того,В противном случае данные будут быстро выведены на экран и пользователь несможет их прочесть.Операция деления по модулю (%) возвращает остаток после деления. То есть выражение (nLine%20) = = 0 истинно при значениях nLine, равных 20, 40, 60, 80.... Словом,идея понятна. Это важный метод, применимый для всех видов циклов, когда нужно выполнять некоторую операцию только с определенной частотой.Функция DumpBuf fer () выводит каждый член массива байтов с использованиемуправляющего элемента форматирования Х2. Х2 хотя и звучит как название какого-тосекретного военного эксперимента, означает всего лишь "вывести число в виде двух шестнадцатеричных цифр" (см. главу 9, "Работа со строками в С # " ) .Диапазон значений byte — от 0 до 255, или O x F F — т.е.
двух шестнадцатеричныхцифр для вывода одного байта достаточно.Вот как выглядят первые 20 строк при выводе содержимого файла output.txt.Даже его собственная мать не узнала бы его в таком виде...Дамп файла С:\C#ProgramsVi\holdtank\Test2\bin\output.txt:001 - 53, 74, 72, 65, 61, 6D, 20, 28, 70, 72,002 - 6F, 74, 65, 63, 74, 65, 64, 29, 0D, OA,003 - 20, 20, 46, 69, 6C, 65, 53, 74, 72, 65,004 - 61, 6D, 28, 73, 74, 72, 69, 6E, 67, 2C,005 - 20, 46, 69, 6C, 65, 4D, 6F, 64, 65, 2C,006 - 20, 46, 69, 6C, 65, 41, 63, 63, 65, 73,007 - 73, 29, OD, OA, 20, 20, 4D, 65, 6D, 6F,008 - 72, 79, 53, 74, 72, 65, 61, 6D, 28, 29,009 - 3B, OD, OA, 20, 20, 4E, 65, 74, 77, 6F,010 - 72, 6B, 53, 74, 72, 65, 61, 6D, OD, OA,011 - 20, 20, 42, 75, 66, 66, 65, 72, 53, 74,012 - 72, 65, 61, 6D, 20, 2D, 20, 62, 75, 66,013 - 66, 65, 72, 73, 20, 61, 6E, 20, 65, 78,014 - 69, 73, 74, 69, 6E, 67, 20, 73, 74, 72,015 - 65, 61, 6D, 20, 6F, 62, 6A, 65, 63, 74,016 - OD, OA, OD, OA, 42, 69, 6E, 61, 72, 79,017 - 52, 65, 61, 64, 65, 72, 20, 2D, 20, 72,018 - 65, 61, 64, 20, 69, 6E, 20, 76, 61, 72,019 - 69, 6F, 75, 73, 20, 74, 79, 70, 65, 73,020 - 20, 28, 43, 68, 61, 72, 2C, 20, 49, 6E,Нажмите <Enter> для вывода очередных 2 0 строкМожно восстановить файл в виде строк из вывода в шестнадцатеричном формате.
0x61 — числовой эквивалент символа а. Буквы, расположены в алфавитном порядке, так что 0x65 должно быть символом е. 0x20 — пробел. Приведенная здесь первая строка выглядит при обычной записи в виде строк как" S t r e a m ( р г " . Интригующе, не правда ли? Полностью коды букв вы можетенайти в разделе "ASCII, table of codes" справочной системы.Эти коды корректны и при использовании набора символов Unicode, который применяется С# по умолчанию (побольше о Unicode вы можете узнать, прогулявшись в Интернете в поисках "Unicode characters").450Часть VII.
Дополнительные главыВот как выглядит вывод программы, если указать неверное имя каталога х:Каталог "х" неверенCould not find a part of the path"C:\C#Programs\LoopThroughFiles\bin\Debug\x".Больше файлов нетНажмите <Enter> для завершения программы...Не впечатляет?...Написание собственного классаколлекции: связанный списокЯ из тех учителей, которые по старинке считают, что сначала следует освоить таблицу умножения, а уж потом давать ученику калькулятор. Так что сейчас вы пройдетесквозь дебри создания собственной коллекции, перед тем как познакомиться со встроенными коллекциями, о которых упоминалось в главе 15, "Обобщенное программирование".
Здесь будут рассмотрены все "болты и гайки", из которых состоит класс коллекции, и как все они объединяются в одно целое.Одним из наиболее распространенных видов контейнеров после массива являетсясвязанный список, каждый объект которого указывает на предыдущий и последующийэлементы списка, т.е. объекты, составляющие список, оказываются соединены в цепочку.Вы используете ссылки на объекты для объединения отдельных узлов в цепь. В каждом таком узле содержатся дополнительные данные, указывающие на следующий узел в цепи.Отдельная переменная, обычно называющаяся ссылкой на голову списка, указывает напервый объект в списке, в то время как хвост списка указывает на его последний элемент.Односвязные списки содержат узлы, связанные только с узлами, следующимиза ними.
По такому списку можно пройти только в одном направлении, следуясвязям между узлами. Дважды связанный список содержит узлы, которые указывают как на последующий, так и на предыдущий узлы. По таким спискамможно проходить в обоих направлениях.Связанный список по сравнению с массивом обладает рядом преимуществ и недостатков.Можно легко вставить элемент в средину списка. Для выполнения вставки программа должна изменить только значения четырех ссылок (в дважды связанномсписке), но это простые, быстро вносимые изменения.Точно так же можно легко удалить элемент из связанного списка.Связанный список при необходимости может расти или уменьшаться. Программаначинает работу с пустым связанным списком, а затем по мере необходимости добавляет и удаляет элементы.Доступ к элементу, располагающемуся следующим, быстр и прост, однако элементы связанного списка не индексированы.
Таким образом, обращение к определенному элементу списка может потребовать проход по всему списку, что весьманеэффективно.Глава 20. Работа с коллекциями451Связанные списки идеально подходят для хранения последовательностей данных,особенно если программа не знает заранее их точное количество (тем не менее следуетсерьезно подумать о возможном применении обобщенного класса List<T>, которыйбыл описан в главе 15, "Обобщенное программирование". Если вам нужен именно связанный список, можно воспользоваться встроенным связанным списком из С# 2.0, а нетем, который разрабатывается в данном разделе.