Смекни!
smekni.com

Общие представления о языке Java 5 (стр. 51 из 68)

File f1=new File(".."); // "." , "/" , "C:/../"

System.out.println("getAbsolutePath(): "+f1.getAbsolutePath());

try{

System.out.println("getCanonicalPath(): "+f1.getCanonicalPath());

}

catch(Exception e){

System.out.println("Исключение от getCanonicalPath() ");

};

System.out.println("exists(): "+f1.exists());

System.out.println("canRead(): "+f1.canRead());

System.out.println("canWrite(): "+f1.canWrite());

Выбор файлов и папок с помощью файлового диалога

При работе с файлами в подавляющем большинстве приложений требуется вызов файлового диалога. В нашем приложении из палитры компонентов (правое верхнее окно среды разработки) перетащим на экранную форму JLabel (“Метка”) – первый компонент в палитре Swing. А затем повторим эту операцию ещё раз. В первой метке мы будем показывать имя выбранного файла, а во второй – путь к этому файлу.

Для того, чтобы вызвать файловый диалог, назначим обработчик события пункту файлового меню openMenuItem (“Открыть...”) – подузел [JFrame]/menuBar[JMenu]/fileMenu[JMenu]/openMenuItem[JMenuItem]. Двойной щелчок по узлу openMenuItem приводит к автоматическому созданию заготовки обработчика openMenuItemActionPerformed и открытию редактора исходного кода.

Сначала мы создаём в приложении объект типа JFileChooser, соответствующий файловому диалогу. Если в начале записать import javax.swing.*, что желательно, то в соответствующих местах кода не потребуется квалификация javax.swing. Но в данном примере импорт не сделан намеренно для того, чтобы было видно, где используются классы данного пакета.

javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser();

Добавим в обработчик необходимый код:

private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {

if(fileChooser.showOpenDialog(null)!= fileChooser.APPROVE_OPTION){

System.out.println("Отказались от выбора");

return;

};

System.out.println("Нажали Open");

jLabel1.setText(fileChooser.getSelectedFile().getName());

jLabel2.setText(fileChooser.getSelectedFile().getParent());

}

В первой строке обработчика вызывается метод fileChooser.showOpenDialog(openMenuItem). Он показывает диалог на экране. В качестве параметра должен быть задан родительский компонент – в этом качестве мы используем пункт меню openMenuItem. Сравнение с переменной класса APPROVE_OPTION позволяет выяснить, была ли выбрана кнопка Open - “Открыть”.

Следует обратить внимание на характерный приём – выход из подпрограммы с помощью оператора return в случае, когда не был осуществлён выбор файла. Неопытные программисты написали бы данный фрагмент кода таким образом:

if(fileChooser.showOpenDialog(openMenuItem)== fileChooser.APPROVE_OPTION){

System.out.println("Нажали Open");

jLabel1.setText(fileChooser.getSelectedFile().getName());

jLabel2.setText(fileChooser.getSelectedFile().getParent());

}

else

System.out.println("Отказались от выбора");

На первый взгляд принципиальной разницы нет. Но при усовершенствовании программы код, соответствующий выбору файла с помощью диалога, заметно разрастётся, а код, соответствующий отказу от выбора, останется тем же. В результате практически весь код обработчика во втором варианте кода окажется вложенным в оператор if – а это может быть несколько страниц кода. В таком коде трудно разбираться. В первом варианте оператор if обладает небольшой областью действия, что позволяет легко разобраться с относящимся к нему кодом.

Можно было бы перенести строку

javax.swing.JFileChooser fileChooser=new javax.swing.JFileChooser()

в обработчик события. В этом случае при каждом нажатии пункта меню “Файл/Открыть…” создавался бы новый объект-диалог. Такой код был бы работоспособен. Но создание диалога является относительно долгим процессом, требующим большого количества ресурсов операционной системы. Поэтому лучше создавать в приложении глобальную переменную, которой назначен диалог. Помимо прочего это позволяет в повторно открываемом диалоге оказываться в той же папке, где происходил последний выбор файла.

Перед вызовом диалога можно программно установить папку, в которой он будет открываться:

File folder=…;

fileChooser.setCurrentDirectory(folder);

Диалог сохранения файла открывается аналогичным образом – showSaveDialog.

Практически всегда при использовании файловых диалогов требуется задавать фильтр, по которому просматриваются файлы. В подавляющем большинстве случаев требуется определённое расширение в имени файла. К сожалению, компонент JFileChooser до сих пор не поддерживает встроенной возможности настраивать фильтр – для этого требуется создание специального класса. Приведём пример простейшего такого класса:

package java_gui_example;

import java.io.*;

public class SimpleFileFilter extends javax.swing.filechooser.FileFilter {

String ext;

SimpleFileFilter(String ext){

this.ext=ext;

}

public boolean accept(File f){

if(f==null)

return false;

if(f.isDirectory()){

return true ;

}

else

return (f.getName().endsWith(ext));

}

/**

* Описание фильтра, возникающее в строке фильтра

* @see FileView#getName

*/

public String getDescription(){

return "Text files (.txt)";

}

}

Использование приведённого класса следующее: задаётся глобальная переменная

javax.swing.filechooser.FileFilter fileFilter=new SimpleFileFilter(".txt");

После чего она используется в обработчике события:

fileChooser.addChoosableFileFilter(fileFilter);

Данный оператор добавляет фильтр в выпадающий список возможных фильтров (масок) файлового диалога. Если добавляется уже существующий фильтр, операция добавления игнорируется.

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

fileChooser.setFileFilter(fileFilter);

Он делает добавленный фильтр текущим, то есть видимым при открытии диалога.

Кроме стандартных диалогов открытия и сохранения файлов имеется возможность вызова диалога с дополнительными программно задаваемыми элементами - с помощью метода showCustomDialog.

Также имеется возможность выбирать несколько файлов. Для этого до вызова диалога требуется задать разрешение на такой выбор:

fileChooser.setMultiSelectionEnabled(true);

Получение массива выбранных файлов после вызова диалога идёт следующим образом:

java.io.File[] files = fileChooser.getSelectedFiles();

if (files != null && files.length > 0) {

String filenames = "";

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

filenames = filenames + "&bsol;n" + files[i].getPath();

}

}

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

fileChooser.setFileSelectionMode(fileChooser.DIRECTORIES_ONLY);

либо и файлы, и папки

fileChooser.setFileSelectionMode(fileChooser.FILES_AND_DIRECTORIES);

Возврат в обычный режим:

fileChooser.setFileSelectionMode(fileChooser.FILES_ONLY);

Для того, чтобы в выбранной папке просмотреть список файлов в папке, с которой связана переменная File folder, используется вызов вида

String[] filenames= folder.list(filter);

Получается массив строк с короткими именами файлов. Используется переменная filter, тип которой является классом, реализующим интерфейс java.io.FilenameFilter. О том, что такое интерфейсы, будет рассказано в отдельном разделе. Пример простейшего такого класса SimpleFilenameFilter:

package java_gui_example;

import java.io.*;

public class SimpleFilenameFilter implements FilenameFilter{

String ext;

public SimpleFilenameFilter(String ext) {

this.ext=ext;

}

public boolean accept(File dir,String fileName){

return ext==""||fileName.endsWith(ext);

}

}

Пример с показом файлов, содержащихся в выбранной папке, в компонент jTextArea1 (текстовая область) типа JTextArea, позволяющий показывать произвольное число строк:

String[] filenamesArray;

File folder=fileChooser.getSelectedFile();

SimpleFilenameFilter filter=new SimpleFilenameFilter("");

String filenames = "";

if(folder.isDirectory()){

filenamesArray=folder.list(filter);

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

filenames = filenames + "&bsol;n" + filenamesArray[i];

};

jTextArea1.setText(filenames);

}

Аналогичный пример вывода выбранных в диалоге имён в режиме “мультиселект”, позволяющем отмечать несколько файлов и/или папок:

java.io.File[] files = fileChooser.getSelectedFiles();

if (files != null && files.length > 0) {

String filenames = "";

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

filenames = filenames + "&bsol;n" + files[i].getPath();

};

jTextArea1.setText(filenames);

};

Работа с потоками ввода-вывода

Стандартные классы Java, инкапсулирующие работу с данными (оболочечные классы для числовых данных, классы String и StringBuffer, массивы и т.д.), не обеспечивают поддержку чтения этих данных из файлов или запись их в файл. Вместо этого используется весьма гибкая и современная, но не очень простая технология использования потоков (Streams).

Поток представляет накапливающуюся последовательность данных, поступающих из какого-то источника. Порция данных может быть считана из потока, при этом она из потока изымается. В потоке действует принцип очереди – “первым вошёл, первым вышел”.

В качестве источника данных потока может быть использован как стационарный источник данных (файл, массив, строка), так и динамический – другой поток. При этом в ряде случаев выход одного потока может служить входом другого. Поток можно представить себе как трубу, через которую перекачиваются данные, причём часто в таких “трубах” происходит обработка данных. Например, поток шифрования шифрует данные, полученные на входе, и при считывании из потока передаёт их в таком виде на выход. А поток архивации сжимает по соответствующему алгоритму входные данные и передаёт их на выход. “Трубы” потоков можно соединять друг с другом – выход одного со входом другого. Для этого в качестве параметра конструктора потока задаётся имя переменной, связанной с потоком - источником данных для создаваемого потока.