Главная страница
Навигация по странице:

  • DirFilter

  • FilenameFilter

  • DirFilter .Метод accept( )

  • String

  • Ответы на вопросы по ревью 4. Java io. Ключевым понятием здесь является понятие потока


    Скачать 1.93 Mb.
    НазваниеJava io. Ключевым понятием здесь является понятие потока
    Дата03.07.2022
    Размер1.93 Mb.
    Формат файлаdoc
    Имя файлаОтветы на вопросы по ревью 4.doc
    ТипДокументы
    #623608
    страница31 из 39
    1   ...   27   28   29   30   31   32   33   34   ...   39

    11: Система ввода/вывода в Java


    Создание хорошей системы ввода/вывода (I/O) является одной из наиболее сложных задач для разработчиков языка.

    Доказательством этому служит наличие множества различных подходов. Сложность задачи видится в охвате всех возможностей. Не только различный исходный код и виды ввода/вывода, с которыми вы можете общаться (файлы, консоль, сетевые соединения), но так же вам необходимо общаться с ними большим числом способов (последовательный, в случайном порядке, буферный, бинарный, посимвольный, построчный, пословный и т.п.).

    Разработчики библиотеки Java атаковали эту проблему путем создания множества классов. Фактически, существует так много классов для системы ввода/вывода в Java, что это может сначала испугать (по иронии, дизайн ввода/вывода Java I/O на самом деле предотвращает взрыв классов). Также произошли значительные изменения в библиотеке ввода/вывода после версии Java 1.0, когда изначально byte-ориентированная библиотека была пополнена char-ориентированными, основанными на Unicode I/O классами. Как результат, есть некоторое количество классов, которые необходимо изучить прежде, чем вы поймете достаточно хорошо картину ввода/вывода Java и ее правильно использовать. Кроме того, достаточно важно понимать историю эволюции библиотеки ввода/вывода, даже если вашей первой реакцией было: “не надоедайте мне историей, просто покажите мне, как использовать это!” Проблема в том, что без исторической перспективы вы постоянно будете смущаться некоторыми классами, определяя, когда вы должны, а когда не должны использовать их.

    Эта глава даст вам введение в различные классы ввод/вывода стандартной библиотеки Java и расскажет о том, как их использовать.

    Класс File


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

    Класс File имеет обманчивое имя — вы можете подумать, что он ссылается на файл, но это не так. Он может представлять либо имя определенного файла, либо имя набора файлов в директории. Если это набор файлов, вы можете опросить набор с помощью метода list( ), который вернет массив String. Есть смысл возвращать массив, а не гибкий класс контейнера, потому что число элементов фиксировано, и если вам нужен список другого директория, вы просто создаете другой объект File. Фактически, “FilePath” был бы лучшим именем для класса. Этот раздел покажет пример использования этого класса, включая ассоциированный FilenameFilter interface.

    Список директории


    Предположим, вы хотите получить список директории. Объект File может выдать его двумя способами. Если вы вызовите list( ) без аргументов, вы получите полный список, содержащийся в объекте File. Однако если вы хотите ограничить список, например, если вы хотите получить все файлы с расширением .java, то вам нужно использовать “фильтр директории”, который является классом, который определяет, как использовать объект File для отображения.

    Здесь приведен код примера. Обратите внимание, что результат без труда будет храниться (в алфавитном порядке) при использовании метода java.utils.Array.sort( ) и AlphabeticComparator, определенного в Главе 9:

    //: c11:DirList.java

    // Отображение списка директории.

    import java.io.*;

    import java.util.*;

    import com.bruceeckel.util.*;
    public class DirList {

    public static void main(String[] args) {

    File path = new File(".");

    String[] list;

    if(args.length == 0)

    list = path.list();

    else

    list = path.list(new DirFilter(args[0]));

    Arrays.sort(list,

    new AlphabeticComparator());

    for(int i = 0; i < list.length; i++)

    System.out.println(list[i]);

    }

    }
    class DirFilter implements FilenameFilter {

    String afn;

    DirFilter(String afn) { this.afn = afn; }

    public boolean accept(File dir, String name) {

    // Получение информации о пути:

    String f = new File(name).getName();

    return f.indexOf(afn) != -1;

    }

    } ///:

    Класс DirFilter “реализует” interface FilenameFilter. Полезно посмотреть, насколько прост FilenameFilter interface:

    public interface FilenameFilter {

    boolean accept(File dir, String name);

    }

    Это говорит о том, что этот тип объекта должен обеспечивать метод, называемый accept( ). Главная цель создания этого класса заключается в обеспечении метода accept( ) для метода list( ), так как list( ) может выполнять “обратный вызов” accept( ) для определения, какое имя файла должно включаться в список. Эта техника часто называется обратным вызовом или иногда функтором (то есть, DirFilter - это функтор, потому что он выполняет работу по поддержанию метода) или Командой Заполнения. Потому что list( ) принимает объект FilenameFilter в качестве аргумента, это означает, что вы можете передать объект любого класса, который реализует FilenameFilter для выбора (даже во время выполнения) поведения метода list( ). Назначение обратного вызова заключается в обеспечении гибкого поведения кода.

    DirFilter показывает, что из-за того, что interface содержит только набор методов, вы не ограничены в написании только этих методов. (Однако вы должны как минимум обеспечить определение для всех методов интерфейса.) В этом случае также создается конструктор DirFilter.

    Метод accept( ) должен принимать объект File, представляющий директорий, в котором находится определенный файл, а String содержит имя этого файла. Вы можете выбрать использовать или игнорировать любой из этих аргументов, но вы, вероятно, как минимум, должны использовать имя файла. Помните, что метод list( ) вызывает метод accept( ) для каждого имени файла в директории, чтобы проверить, какой из них должен быть включен — на это указывает тип boolean результата, возвращаемого accept( ).

    Чтобы убедится, что элемент, с которым вы работаете, является всего лишь именем файла и не содержит информации о пути, все, что вам нужно сделать, это получить объект String и создать из него объект File, затем вызвать getName( ), который отсекает всю информацию о пути (платформонезависимым способом). Затем accept( ) использует метод indexOf( ) класса String, чтобы убедится, что искомая строка afn присутствует в любом месте имени файла. Если afn найдено в строке, возвращаемым значением является начальный индекс afn, а если не найдено, возвращаемым значением является -1. Имейте в виду, что это простой поиск строк и не имеет “глобальных” выражений подстановочных символов, таких как fo?.b?r*”, которые являются более сложными в реализации.

    Метод list( ) возвращает массив. Вы можете опросить этот массив о его длине, а затем пройтись по нему, выбирая элементы массива. Эта способность легкого прохода по массиву вне методов и в методах является значительным улучшением по сравнению с поведением C и C++.

    Анонимные внутренние классы


    Это пример идеален для того, чтобы быть переписанным с использованием анонимных внутренних классов (описанных в Главе 8). В качестве первой пробы, создадим метод filter( ), который возвращает ссылку на FilenameFilter:

    //: c11:DirList2.java

    // Использование анонимных внутренних классов.

    import java.io.*;

    import java.util.*;

    import com.bruceeckel.util.*;
    public class DirList2 {

    public static FilenameFilter

    filter(final String afn) {

    // Создание анонимного внутреннего класса:

    return new FilenameFilter() {

    String fn = afn;

    public boolean accept(File dir, String n) {

    // Получаем информацию о пути:

    String f = new File(n).getName();

    return f.indexOf(fn) != -1;

    }

    }; // Конец анонимного внутреннего класса

    }

    public static void main(String[] args) {

    File path = new File(".");

    String[] list;

    if(args.length == 0)

    list = path.list();

    else

    list = path.list(filter(args[0]));

    Arrays.sort(list,

    new AlphabeticComparator());

    for(int i = 0; i < list.length; i++)

    System.out.println(list[i]);

    }

    } ///:

    Обратите внимание, что аргумент для filter( ) должен быть final. Это требуется анонимному внутреннему классу, так как он использует объект внешней части кода, по отношению к нему.

    Это лучший дизайн, потому что класс FilenameFilter теперь тесно связан с DirList2. Однако вы можете выбрать этот подход на один шаг раньше, и определить анонимный внутренний класс как аргумент list( ), в этом случае программа будет даже меньше:

    //: c11:DirList3.java

    // Построение анонимного внутреннего класса "на месте".

    import java.io.*;

    import java.util.*;

    import com.bruceeckel.util.*;
    public class DirList3 {

    public static void main(final String[] args) {

    File path = new File(".");

    String[] list;

    if(args.length == 0)

    list = path.list();

    else

    list = path.list(new FilenameFilter() {

    public boolean

    accept(File dir, String n) {

    String f = new File(n).getName();

    return f.indexOf(args[0]) != -1;

    }

    });

    Arrays.sort(list,

    new AlphabeticComparator());

    for(int i = 0; i < list.length; i++)

    System.out.println(list[i]);

    }

    } ///:

    Теперь аргумент у main( ) является final, так как анонимный внутренний класс напрямую использует args[0].

    Здесь показано как анонимный внутренний класс позволяет создать быстрые и грязные классы для решения проблемы. Так как все в Java вертится вокруг классов, это может быть полезной техникой написания программ. Одна из выгод в том, что программа содержит код, который решает определенную проблему, изолированную в одном месте. С другой стороны, это не всегда легче для чтения, так что вы должны использовать это с умом.

    Поиск и создание директориев


    Класс File - это больше, чем просто представление существующего файла или директория. Вы также можете использовать объект File для создания новой директории или целого пути директорий, если этот путь не существует. Вы можете также взглянуть на характеристики файлов (размер, дату последней модификации, доступ на чтение/запись), посмотреть, представляет ли объект File файл или директорий, и удалить файл. Эта программа показывает некоторые методы, поддерживаемые классом File (смотрите HTML документацию на java.sun.com чтобы увидеть полный набор):

    //: c11:MakeDirectories.java

    // Демонстрация использования класса File

    // для создания и манипулирования файлами.

    import java.io.*;
    public class MakeDirectories {

    private final static String usage =

    "Usage:MakeDirectories path1 ...\n" +

    "Creates each path\n" +

    "Usage:MakeDirectories -d path1 ...\n" +

    "Deletes each path\n" +

    "Usage:MakeDirectories -r path1 path2\n" +

    "Renames from path1 to path2\n";

    private static void usage() {

    System.err.println(usage);

    System.exit(1);

    }

    private static void fileData(File f) {

    System.out.println(

    "Absolute path: " + f.getAbsolutePath() +

    "\n Can read: " + f.canRead() +

    "\n Can write: " + f.canWrite() +

    "\n getName: " + f.getName() +

    "\n getParent: " + f.getParent() +

    "\n getPath: " + f.getPath() +

    "\n length: " + f.length() +

    "\n lastModified: " + f.lastModified());

    if(f.isFile())

    System.out.println("it's a file");

    else if(f.isDirectory())

    System.out.println("it's a directory");

    }

    public static void main(String[] args) {

    if(args.length < 1) usage();

    if(args[0].equals("-r")) {

    if(args.length != 3) usage();

    File

    old = new File(args[1]),

    rname = new File(args[2]);

    old.renameTo(rname);

    fileData(old);

    fileData(rname);

    return; // Выход из main

    }

    int count = 0;

    boolean del = false;

    if(args[0].equals("-d")) {

    count++;

    del = true;

    }

    for( ; count < args.length; count++) {

    File f = new File(args[count]);

    if(f.exists()) {

    System.out.println(f + " exists");

    if(del) {

    System.out.println("deleting..." + f);

    f.delete();

    }

    }

    else { // Не существует

    if(!del) {

    f.mkdirs();

    System.out.println("created " + f);

    }

    }

    fileData(f);

    }

    }

    } ///:

    В fileData( ) вы можете видеть различные способы исследования файла для отображения информации о файле или о пути директории.

    Первый метод, который вызывается main( ) - это renameTo( ), который позволяет вам переименовать (или переместить) файл по введенному новому путь, представленному аргументом, который является другим объектом типа File. Это так же работает с директориями любой длины.

    Если вы поэкспериментируете с приведенной выше программой, вы обнаружите, что вы можете создать путь директорий любой сложности, потому что mkdirs( ) будет делать всю работу за вас.
    1   ...   27   28   29   30   31   32   33   34   ...   39


    написать администратору сайта