Главная страница

Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция


Скачать 25.04 Mb.
НазваниеС. Н. Тригуб Перевод с английского и редакция
АнкорJava. Полное руководство. 8-е издание.pdf
Дата28.02.2017
Размер25.04 Mb.
Формат файлаpdf
Имя файлаJava. Полное руководство. 8-е издание.pdf
ТипДокументы
#3236
страница61 из 90
1   ...   57   58   59   60   61   62   63   64   ...   90
import java.io.*;
Глава 20. Исследование N10
6 6 1
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
public class MappedChannelWrite {
public static void main(String a r g s []) {
// Получить канал для файла в пределах блока try-с-ресурсами.
try ( FileChannel fChan = (FileChannel)
Files.newByteChannel(Paths.g e t ("test.tx t "),
StandardOpenOption.WRITE,
StandardOpenOption.R E A D ,
StandardOpenOption.CREATE) )
{
// Затем сопоставить файл с буфером mBuf ТЕ Записать несколько байтов в буфер
for(int i=0; i<26; i
+
+ )
mBuf.put((byte) (1A '
+ i));
} c a tch(InvalidPathException e) {
System.out.println("Path Error " + e ) ;
} catch (IOException e) {
System.out.println("I/O Error " + e ) Как можно заметить, здесь нет никаких явных операций записи непосредственно в канал. Поскольку буфер mBuf сопоставлен с файлом, изменения в буфере автоматически отражаются в основном файле.
Копиро вание файла с использованием Система NIO упрощает несколько типов файловых операций. Хотя мы немо жем рассмотреть их все, пример даст вам общее представление о том, что доступно. Следующая программа копирует файл непосредственно одним методом NIO сору ( ), являющимся статическим методом класса F i l e s . Он имеет несколько форм. Вот та, которую мы будем использовать Path copy(Path ист н азн ,
CopyOption ... как throws Файл, определенный параметром ист, копируется в файл, определенный параметром на зн . То, как будет выполняться копирование, определяет параметр как Поскольку это параметр для аргумента переменной длины, он может отсутствовать. Если он определен, то может передать одно или несколько следующих значений, которые допустимы для всех файловых систем.
StandardCopyOption.COPY_ATTRIBUTES
Требовать копирования атрибутов файла
StandardLinkOption.NOFOLLOW_LINKS
Не следовать по символическим ссылкам
StandardCopyOption.REPLACE_EXISTING
Перезаписать прежний файл
В зависимости от реализации, могут поддерживаться и другие возможности.
Следующая программа демонстрирует метод сору. Исходный и результирующие файлы определяются в командной строке, причем исходный файл указывается первым. Обратите внимание на размер программы. Вы могли бы сравнить эту версию программы копирования файла с аналогом из главы 13. В результате ока

6 6 Часть II. Библиотека Java
жется, что та часть программы, которая фактически копирует файл, существенно короче в версии NIO, представленной здесь Копирование файла с использованием N10. Требует JDK 7.

import java.io.*;
import java.nio.*;
import java.nio.channels.* ;
import java.n i o .file.*;
public class NIOCopy {
public static void main(String a r g s []) {
if(args.length != 2) {
System.out.println("Usage:
Copy from to");
return;
}
try {
Path source = Paths.get(args[0]);
Path target = Paths.get(args[1]);
// Скопировать файл iles.c o p y (source,
target,
StandardCopyOption.REPLACE_EXISTING);
} c a t c h (InvalidPathException e) {
System.out.println("Path Error " + e ) ;
} catch (IOException e) {
System.out.println("I/O Error " + e ) Использование системы N10 для потокового ввода-вывода

Начиная с JDK 7 вы можете использовать систему NIO для открытия потока ввода-вывода. Получив объект интерфейса, откройте файл, вызвав статический метод newlnputstream (
) или newOutputStream ()
, определенные в классе
Files. Эти методы возвращают поток, связанный с определенным файлом. В любом случае поток затем может быть использован так, как описано в главе 19; применимы те же методики. Преимущество использования объекта интерфейса
Path для открытия файла в том, что доступны все средства системы Чтобы открыть файл для потокового ввода, используйте метод
Files .
newln­
putstream ()
. Он имеет следующую форму Inputstream newlnputstream(Path путь. как throws Здесь параметр путь определяет открываемый файла параметр как- то, как файл будет открыт. Это должно быть одно или несколько значений, определенных описанным ранее классом
StandardOpenOpt ion. Конечно, применимы только те значения, которые относятся к потоку ввода) Если параметр не определен, то файл открывается так, как будто было передано значение
StandardOpenOpt ion.
После открытия вы можете использовать любой из методов, определенных в классе
Inputstream. Например, вы можете использовать метод read
() для чтения байтов из файла
Глава 20. Исследование N10
6 6 Следующая программа демонстрирует использование потокового ввода-вывода на базе NIO. Это программа
ShowFile из главы 13, переделанная так, чтобы для открытия файла и получения потока использовались средства NIO. Как можно заметить, это очень похоже на первоначальный вариант, за исключением использования интерфейса и метода newlnputStream ().
/* Отображает текстовый файл, используя потоковый код Требует JDK Чтобы использовать эту программу, укажите имя файла, который хотите просмотреть. Например, чтобы просмотреть файл по имени
T E S T .T X T ,
используйте следующую командную строку ShowFile TEST.TXT
*/
import java.io.*;
import java.nio.file.* ;
class ShowFile {
public static void main(String a r g s [])
{
int i ;
// Сначала удостовериться, что имя файла было указано
if(args.length != 1) {
System.out.pri n t l n ("Usage:
ShowFile filename");
return;
}
// Открыть файл и получить связанный с ним поток (InputStream fin = Files.newlnputstream(Paths.get(args[0])))
{
do {
i = fi n .r e a d ();
if(i != -1) System.out.print((char) i);
} w h i l e (i != -1);
} c a t c h (InvalidPathException e) {
System.out.println("Path Error " + e ) ;
} c a t c h (IOException e) {
System.out.pri n t l n ("I/O Error " + e ) Поскольку поток, возвращенный методом newlnputstream ()
, является обычным, он применяется как любой другой поток. Например, вы можете заключить поток внутрь буферизованного потока, такого как поток класса
Buf f eredlnputstream, чтобы обеспечить буферизацию так, как показано далее Теперь все операции чтения будут автоматически буферизованы.
Чтобы открыть файл для вывода, используйте метод
Files.newOutput
-
Stream ()
. Он имеет следующую форму OutputStream newOutputStream(Path путь OpenQption ... как)
throws Здесь параметр путь определяет открываемый файла параметр как то, как файл будет открыт. Это должно быть одно или несколько значений, определенных

6 6 Часть II. Библиотека описанным ранее классом
S ta n d a rd O p e n O p t io n . Конечно, применимы только те значения, которые относятся к потоку вывода) Если параметр не определен, то файл открывается так, как будто были переданы значения
S ta n d a rd O p e n O p t i o n . WRITE,
S ta n d a rd O p e n O p t i o n . CREATE и
S ta n d a rd O p e n O p t i o n . TRUNCATE_EXI Способ использования метода n e w O u tp u tS tr e a m
() подобен описанному ранее для метода n e w l n p u t s t r e a m ( )
. После открытия можете использовать любой метод, определенный в классе
O u t p u tS t r e a m . Например, можете использовать метод w r i t e
() для записи байтов в файл. Вы можете также заключить поток в байтовый поток класса
B u f f e r e d O u t p u t S t r e a m , чтобы буферизовать его.
Следующая программа демонстрирует метод n e w O u tp u tS tr e a m
() в действии. Она записывает алфавит в файл по имени t e s t . t x t . Обратите внимание на использование буферизованного ввода-вывода.
// Демонстрация потокового вывода на базе N10. Требует JDK 7.
import java.io.*;
import java.nio.file.*;
class NIOStreamWrite {
public static void main(String a r g s [])
{
// Открыть файл и получить связанный с ним поток
try (OutputStream fout =
new BufferedOutputStream(
F iles.newOutputStream(Paths.g e t ("tes t .txt"))) )
{
// Записать в поток несколько байтов
for(int i = 0 ; i < 2 6 ; i + + )
fout.write((byte)('A '
+ i));
} c a t c h (InvalidPathException e) {
System.out.println("Path Error " + e ) ;
} c a t c h (IOException e) {
System.out.println("I/O Error: " + e ) Использование системы N10 для операций файловой системы
В начале главы 19 был исследован класс
F i l e , расположенный в пакете j a v a . i o . Как упоминалось, класс
F i l e имеет дело с файловой системой и различными атрибутами файла, такими как только для чтения, скрытый и т.д. Он также используется для получения информации о пути файла. С появлением комплекта JDK 7 интерфейсы и классы, определенные системой N10.2, предлагают лучший способ выполнения этих операций. К их преимуществам относятся поддержка символических ссылок, лучшая поддержка обхода дерева каталогов, улучшенная обработка метаданных и многое другое. В следующих разделах приведены примеры двух популярных операций файловой системы получение информации о пути и файле, а также о содержимом каталога.
Помните! Если хотите заменить устаревший код, использующий класс

j a v a . i o . F i l e , на новый, использующий интерфейс

P a th , можете использовать метод

t o P a t h (), чтобы получить экземпляр интерфейса
P a th из экземпляра класса
F i l e . Метод
t o P a t h () был добавлен к классу
F i l e в JDK 7.
Глава 20. Исследование N10
6 6 Получение информации о пути и файле Информация о пути может быть получена при помощи методов, определенных интерфейсом
Path. Некоторые, связанные с файлом атрибуты, описанные интерфейсом
Path такие, как скрытый, получают при помощи методов, определенных в классе
Files. Здесь используются такие методы интерфейса
Path, как getName (), getParent
() и toAbsolutePath
(), акласс
Files предоставляет такие методы, как isExecutable
(), isHidden
(), isReadable
(), isWritable
() и exists
(). Они представлены в приведенных выше табл. 20.5 и Внимание Такие методы, как

isExecutable (), isReadable(), isWritable () и
exists (), следует использовать осторожно, поскольку состояние файловой системы после вызова может измениться, в программе может произойти сбой. В такой ситуации может иметь значение защита.
Другие атрибуты файла получают, затребовав их список, создаваемый при вызове метода
Files .
readAttributes
(). В программе этот метод применяется для получения связанного с файлом объекта интерфейса, но общий подход применим и к другим типам атрибутов.
Следующая программа демонстрирует некоторые методы интерфейса и класса
Files наряду с несколькими методами, предоставленными интерфейсом
BasicFileAttributes. Эта программа подразумевает, что файл по имени test.
txt существует в каталоге examples, внутри текущего каталога Получить информацию о пути и файле Требует JDK 7.
import java.io.*;
import java.nio.file.* ;
import j a v a .n i o .file.attribute.*;
class PathDemo {
public static void main(String a r g s []) {
Path filepath = Paths.g e t ("examples\\test.txt");
System.out.println("File Name: " + filepath.getName(1));
System.out.println("Path: " + filepath);
System.out.println("Absolute Path: " +
filepath.toAbsolutePath());
System.out.println("Parent:
" + filepath.getParent());
if(Files.exists(filepath))
System.out.println("File exists");
else
System.out.println("File does not exist");
try {
if(Files.isHidden(filepath))
System.out.println("File is hidden");
else
System.out.println("File is not hidden");
} ca t c h (IOException e) {
System.out.println("I/O Error: " + e ) ;
}
F iles.isWritable(filepath);
System.out.println("File is writable");
Files.isReadable(filepath);
System.out.println("File is readable");
Часть II. Библиотека Java
try {
BasicFileAttributes attribs =
Files.readAttributes(filepath, BasicFileAttributes.class)
if(attribs.isDirectory())
System.out.println("The file is a directory");
else
System.out.pri n t l n ("The file is not a directory");
if(attribs.isRegularFile())
System.out.p r i ntln("The file is a normal file");
else
System.out.println("The file is not a normal file");
if(attribs.isSymbolicLink())
System, out .print'ln ("The file is a symbolic link");
else
System.out.println("The file is not a symbolic link");
System.out.println("File last modified: " +
attribs.lastModifiedTime());
System.out.println("File size: " + attribs.s i z e () +
" Bytes");
} c a t c h (IOException e) {
System.out.println("Error reading attributes: " + e ) Если запустить эту программу из каталога
My D i r , внутри которого есть каталог e x a m p le s , содержащий файл t e s t . t x t , то увидите вывод, подобный представленному ниже. (Конечно, размер файла и время будут иными Name: test.txt

Path: examples\test.txt
Absolute Path: C:\MyDir\examples\test.txt
Parent:
examples
File exists
File is not hidden
File is writable
File is readable
The file is not a directory
The file is a normal file
The file is not a symbolic link
File last modified: 2010-09-01T18:20:46.380445Z
File size: 18 Если вы используете компьютер с файловой системой FAT (те. файловой системой DOS), то могли бы попробовать использовать методы, определенные интерфейсом
D o s F i l e A t t r i b u t e s . Если вы используете систему, совместимую сто попробуйте использовать методы, определенные интерфейсом o s i x F i l e A t t r i b u t e s Перечисление содержимого каталога

Если путь описывает каталог, то вы можете прочитать содержимое этого каталога, используя статические методы, определенные в классе
F i l e s . Для этого вы получаете сначала поток каталога, вызвав метод n e w D i r e c t o r y S t r e a m
() при передаче ему объекта интерфейса, описывающего каталог. Одна из форм метода n e w D i r e c t o r y S t r e a m
( ) приведена ниже
Глава 20. Исследование N10
6 6 7
static DirectoryStream newDirectoryStream(Path
путьКкаталогу)
throws Здесь аргумент
путьКкаталогу инкапсулирует путь к каталогу. Метод возвращает объект
DirectoryStream
, применяемый для получения содержимого каталога. Он передает исключение
IOException, в случае ошибки ввода-вывода, и исключение
NotDirectoryException класс которого происходит от класса
IOException), если определенный путь не является каталогом. Возможна также передача исключения
SecurityException, если доступ к каталогу не разрешен.
Поскольку объект
DirectoryStream реализует интерфейс
Auto­
Closeable, он может контролироваться оператором
try-с-ресурсами. Он также реализует интерфейс Это значит, что вы можете получить содержимое каталога, перебрав объект
DirectoryStream. При переборе каждая запись каталога представляется экземпляром интерфейса
Path. Простейший способ перебора объекта
DirectoryStream
— использование цикла for в стиле for-each. Однако следует уяснить, что итератор, реализованный объектом
DirectoryStream
, может быть получен только однажды для каждого экземпляра. Таким образом, метод iterator!) может быть вызван только однажды и цикл for в стиле for-each может быть выполнен только один раз.
Следующая программа отображает содержимое каталога по имени
My
Dir.
// Отображает каталог. Требует JDK 7.
import java.io.*;
import java.nio.file.*;
import j a v a .n i o .file.attribute.*;
class DirList {
public static void main(String a r g s []) {
String dirname = "WMyDir";
// Получить и обработать поток каталога в пределах блока try.
try (
DirectoryStream dirstrm =
Files.newDirectoryStream(Paths.get(dirname))
)
{
System.out.p r intln("Directory of " + dirname);
// Поскольку DirectoryStream реализует интерфейс Iterable,
// мы можем использовать цикл "foreach" для отображения
// каталога entry :
dirstrm) {
BasicFileAttributes attribs =
Files.readAttributes(entry, BasicFileAttributes.class);
if(attribs.isDirectory())
System.out.print(" ");
else
System.out.p r i n t ("
");
System.out.println(entry.getName(1));
}
} cat c h (InvalidPathException e) {
System.out.p r intln("Path Error " + e ) ;
} catch(NotDirectoryException e) {
System.out.println(dirname + " is not a directory.");
} catch (IOException e) {
System.out.println("I/O Error: " + e ) ;
}
Часть II. Библиотека Вот пример вывода этой программы of \MyDir
DirList.class
DirList.j ava
examples
T e s t Вы можете отфильтровать содержимое каталога двумя способами. Самый простой — использование такой версии метода n e w D ir e c to r y S tr e a m ().
static DirectoryStream newDirectoryStream(Path
путьКкаталогу,
String шаблон throws В этой версии будут получены только те файлы, имена которых соответствуют шаблону, определенному параметром шаблон Для параметра шаблон вы можете определить или полное имя файла, или объект g lo b . Объект g l o b — это строка, определяющая общий шаблон, которому будет соответствовать один или несколько файлов, и содержащая знакомые символы * и ?. Они соответствуют любому количеству любых символов и любому символу соответственно. Ниже приведены соответствия в пределах объекта g lo b .
* Соответствует любому количеству различных символов в каталоге
[
символы]
Соответствует любому символу в символы.
Символы * ив пределах символы будут рассматриваться как обычные символы, а не как символы шаблона. При помощи дефиса может быть указан диапазон, такой как
[x-z]
{ список до Ь Соответствует любому объекту
glob, заданному в разделяемом запятыми списке объектов
glob в список до Ь
Вы можете определить символы * и ?, используя последовательности \ * и \ ?. Чтобы определить символ \ , используйте последовательность \ \ . Вы можете поэкспериментировать с объектом glob, подставляя его в вызов метода newDirec­
toryStream
() предыдущей программы "В результате получится поток каталога, содержащий только те файлы, имена которых начинаются или с "Path" или "Dir" и имеют расширение "java" или "class". Таким образом, это соответствовало бы таким именам, как
DirList. j ava и
PathDemo .
j ava, ноне Еще один способ фильтрации каталога заключается в использовании такой версии метода newDirectoryStream ().
static DirectoryStream newDirectoryStream(Path
путьКкаталогу,
DirectoryStream.Filter
файловыйфильтр)
throws Здесь
DirectoryStream. Filter
— это интерфейс, определяющий следующий метод Т элемент throws В данном случае типом Т будет
Path. Если вы хотите включить элемент в список, возвращается значение true. В противном случае возвращается значение false. Эта форма метода newDirectoryStream
() предоставляет возможность фильтрации каталога на основании чего-то отличного от имени файла. Например, вы можете фильтровать на основании размера, даты создания, даты модификации или атрибута.
Следующая программа демонстрирует этот процесс. Здесь перечислены только те файлы, которые допускают запись
Глава 20. Исследование N10
6 6 9
// Отображает только те файлы каталога, которые допускают запись java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
class DirList {
public static void main(String a r g s []) {
String dirname = "WMyDir";
// Создать фильтр, возвращающий true только для
// записываемых файлов how =
new DirectoryStream.Filter
() {

public boolean accept(Path filename) throws IOException {
if(Files.isWritable(filename))
return true;
return false;
}
};
// Получить и использовать поток каталога для записываемых файлов (DirectoryStream dirstrm =
Files.newDirectoryStream(Paths.get(dirname),
how) )
{
System.out.println("Directory of " + dirname);
for (Path entry :
dirstrm.) {
BasicFileAttributes attribs =
F i les.readAttributes(entry,
BasicFileAttributes.class);
if(attribs.isDirectory ())
System.out.p r i n t ("
");
else
System.out.p r i n t ("
");
System.out.println(entry.getName(1));
}
} c a t c h (InvalidPathException e) {
System.out.println("Path Error " + e ) ;
} catch(NotDirectoryException e) {
System.out.println(dirname + " is not a directory.");
} catch (IOException e) {
System.out.println("I/O Error: " + e ) Использование метода w a l k F i l e T r e e ( ) для перечисления дерева каталогов

В предыдущих примерах мы получали содержимое только одного каталога. Но иногда необходимо получить список файлов в дереве каталогов. В прошлом это было настоящей проблемой, но система N10.2 существенно облегчает это, поскольку теперь вы можете использовать определенный в классе
F i l e s метод
w a l k F i l e T r e e (), способный обработать дерево каталогов. Этот метод имеет две формы в данной главе используется такая Path walkFileTree(Path корень FileVisitor
fv)
throws IOException

6 7 Часть II. Библиотека Начальный пункт обхода каталога передается в параметре корень Экземпляр интерфейса передается в параметре Реализация интерфейса определяет способ обхода дерева каталогов, а также позволяет обращаться к информации каталога. При ошибке ввода-вывода передается исключение. Возможна также передача исключения Интерфейс определяет то, как посещаются файлы при обходе дерева каталогов. Это обобщенный интерфейс, который объявляется так Для использования в методе walkFileTree
( ) , параметр типа Т будет иметь тип интерфейса или любой тип, производный от него. Винтер фей се
FileVisitor определены методы , перечисленные в табл. Таблица 20.11. Методы, определенные в интерфейсе

F i l e V i s i t o r
Метод
Описание
FileVisitResult
postVisitDirectory (Т каталог исключение throws
IOException
FileVisitResult
preVisitDirectory (T каталог атрибуты)
throws IOException
FileVisitResult visitFile (T файл,
BasicFileAttributes атрибуты)
throws IOException
FileVisitResult
visitFileFailed (T файл,
IOException исключение throws Вызывается после посещения каталога. Каталог передается в параметре каталога любое исключение
IOExcept
ion
— в параметре исключение. Если параметр исключение содержит значение
null, значит, никакого исключения не произошло. Результат возвращается Вызывается перед посещением каталога. Каталог передается в параметре каталога связанные с ним атрибуты — в параметре атрибуты.
Результат возвращается. Чтобы исследовать каталог, возвратите значение
FileVisitResult.
CONTINUE Вызывается при посещении файла. Файл передается в параметре файла связанные с ним атрибуты — в параметре атрибуты.
Результат воз­
вращается
Вызывается при неудачной попытке посещения файла. Файл, который потерпел неудачу, передается в параметре файла исключение

— в параметре исключение. Результат возвращается_______________________
О б рати те внимание на то, что каждый метод возвращает значение перечисления. Это перечисление определяет следующие значения.
CONTINUE
SKIP_SIBLINGS
SKIP_SUBTREE
TERMINATE
Вообщ е, для продолжения обхода каталога и каталогов внутри него метод должен возвратить значение. Для метода p r e V i s i t D i r e c t o r y () возвратите значение, чтобы пропустить каталоги его содержимое, а также предотвратить вызов метода. Чтобы пропустить только каталоги подкаталоги, возвратите значение. Чтобы остановить обход каталога, возвратите значение Конечно, вполне можно создать собственный класс посещения, который реализует эти методы, определенные интерфейсом, но обычно вы не будете поступать так, поскольку предоставляется его простая реализация, класс
S i m p l e F i l e V i s i t o r . Достаточно переопределить заданную по умолчанию реализацию метода или методов, которые вас интересуют. Вот краткий пример, который иллюстрирует этот процесс. Он отображает все файлы в дереве каталогов, корнем которого является каталог \M yD ir. Обратите внимание на размер этой программы Простой пример использования метода walkFileTree() для отображения
// дерева каталогов. Требует JDK 7.
Глава 20. Исследование N10
6 7 1
import java.io.*;
import j a v a . n i o .f i l e .* ;
import j a v a .n i o .f i l e .a t t r i b u t e .*;
// Создать специальную версию S i m p l e F i l e V i s i t o r ,
переопределяющую метод leV isitResult v i s i t F i l e (Path path,
B as icF ile Att rib ute s attribs)
throws IOException
{
S y s t e m . o u t . p r i n t l n ( p a t h ) ;
return F i l e V i s i t R e s u l t .CONTINUE;
}
}
class DirTreeList {
public static voi d m a in ( Str ing a r g s []) {
String dirname = " W M y D i r " ;
S y s t e m . o u t . p r i n t l n ("Directory tree starting wi th " +
dirname + ": \ n" );
try {
Files .walkFileTree (Paths .
get (dirname) ,
ne w M y F i l e V i s i t o r ());
} catch (IOException exc) {
S y s t e m . o u t . p r i n t l n ("I/O E r r o r " Вот пример вывода программы, выполненной для того же каталога My D ir, что и ранее. В этом примере вложенный каталог e x a m p le s содержит только один файл по имени M yProgram . j av a.
Directo ry tree starting with \MyDir:
\My Dir \D ir L is t .class ч Di r\ Di r Li s t. j ava
\ M yD ir \ ex a mp l es \ My P ro g ra m .j ava
\M yD i r\T est В этой программе класс M y F i l e V i s i t o r расширяет класс S i m p l e F i l e V i s i t o r , переопределяя только метод v i s i t F i l e ( ) . B этом примере метод v i s i t F i l e () просто отображает их, но вполне можно достичь и более сложных функциональных возможностей. Например, вы могли бы фильтровать файлы или выполнять сними такие действия, каких копирование на устройство резервирования. Для простоты использовался именованный класс, переопределяющий метод v i s i t ­
F i l e ( ), но вполне можно также использовать анонимный внутренний класс.
И последний момент используя j a v a . n i o . f i l e . W a tc h S e rv ic e , можно отследить изменения в каталоге.
Примеры использования каналов до JDK Прежде чем завершить эту главу, следует рассмотреть еще один аспект системы
NIO. В приведенных выше разделах использовались некоторые новые средства, добавленные в систему NIO с появлением JDK 7. Однако осталось еще много кода, написанного до JDK 7, который необходимо поддерживать, а возможно, и преобразовывать для использования новых средств. Поэтому следующие разделы де

6 7 Часть II. Библиотека Java
монстрируют чтение и запись файлов с использованием системы NIO до JDK 7. Некоторые из приведенных выше примеров переделаны так, чтобы использовать предыдущие средства NIO, а не новые (N10.2). Это значит, что примеры в этом разделе будут работать с версиями Java до JDK Основное отличие между прежним кодом NIO и новым заключается в интерфейсе
P a th , который был добавлен с появлением JDK 7. Таким образом, прежний код не использует интерфейс
P a t h для описания файла или открытия канала к нему. Кроме того, прежний код не использует операторы t r y -с-ресурсами, поскольку автоматическое управление ресурсами также было добавлено только в JDK Помните В примерах этого раздела описывается работа устаревшего кода N10. Материал этого раздела предназначен для тех программистов, которые продолжают работать с кодом написанным до появления JDK 7, или используют прежний компилятор. Новый код должен использовать средства N10, добавленные JDK Чтение из файла до JDK Здесь приведено два предыдущих примера канального ввода из файла, переделанных для использования средств только до JDK 7. В первом примере выполняется чтение файла при резервировании буфера вручную и последующем явном выполнении операций чтения. Во втором примере осуществляется сопоставление файла, автоматизирующее процесс.
П ри использовании версий Java до JDK 7, для чтения файла с использованием канала и зарезервированного вручную буфера, вы сначала открываете файл для ввода, используя объект класса
F i l e I n p u t S tr e a m , точно также как описано в главе 19. Затем получаете канал к этому файлу, вызвав метод g e t C h a n n e l
() для объекта класса
F i l e l n p u t s t r e a m . Его общая форма такова Она возвращает объект класса
F i 1 e C h a n n e 1
, инкапсулирующий канал для файловых операций. Затем вызов метода a l l o c a t e
() резервирует буфер. Поскольку файловые каналы работают с байтовыми буферами, выбудете использовать метод a l l o c a t e ( ) , определенный в классе
B y te B u f f e r , как было описано ранее.
Следующая программа демонстрирует чтение и отображение файла по имени t e s t . t x t через канал с использованием явных операций ввода для версий Java до JDK 7.
// Использование каналов для чтения файла. Версия до JDK 7.
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class ExplicitChannelRead {
public static void main(String a r g s []) {
Filelnputstream fin = null;
FileChannel fChan = null;
ByteBuffer mBuf;
int count;
try {
// Сначала открыть файл для ввода
fin = new Filelnputstream("tes t .txt");
// Затем получить канал к этому файлу
fChan = fIn.getChannel();
// Зарезервировать буфер
Глава 20. Исследование N10
6 7 3
mBuf = ByteBuffer.allocate(128);
do {
// Читать в буфер = fChan.read(mBuf);
// Остановиться при достижении конца файла
if(count != -1) {
// Подготовить буфер для чтения
m B u f .rewind();
// Читать байты в буфер и отображать их
/ / на экране как символы
for(int i=0; i < count; i++)
System.out.print((char)m B u f .g e t ());
}
} while(count != -1);
System.out.println();
} catch (IOException e) {
System.out.p r intln("I/O Error " + e ) ;
} finally {
try {
if(fChan 1= null) fChan.cl o s e (); // закрыть канал
} c a t c h (IOException e) {
System.out.println("Error Closing Channel.");
}
try {
if (fin 1
= null) fin.closeO; // закрыть файл
} c a t c h (IOException e) {
System.out.println("Error Closing Обратите внимание на то, что в этой программе файл открывается с использованием конструктора класса F i l e l n p u t S t r e a m , а ссылка на этот объект присваивается объекту f i n . Затем, при вызове метода g e t C h a n n e l () объекта f i n , создается канал соединения с файлом. После этого программа работает, как в версиях для JDK 7, представленных ранее. Короче говоря, затем программа вызывает метод a l l o c a t e () класса B y te B u f f e r , чтобы зарезервировать буфер для размещения содержимого файла при чтении. Используется байтовый буфер, поскольку класс F i le C h a n n e l работает с байтами. Ссылка на этот буфер хранится в объекте mBuf. Затем содержимое файла читается в буфер mBuf по одному буферу зараз при помощи метода r e a d (). Количество прочитанных байтов хранится в переменной c o u n t. Затем буфер возобновляется вызовом метода r e w in d (). Этот вызов необходим, поскольку после вызова метода r e a d () текущая позиция буфера находится в конце, а ее следует вернуть в начало буфера, чтобы байты из буфера mBuf могли быть прочитаны при вызове метода g e t (). Когда будет достигнут конец файла, метод r e a d () возвратит значение -1 . Когда это произойдет, программа завершит работу явно, закрыв канал и файл.
Другой способ чтения файла состоит в его сопоставлении с буфером. Как объяснялось ранее, основное преимущество этого подхода в том, что буфер автоматически получает содержимое файла. Никаких явных операций чтения ненужно. Чтобы сопоставить и прочитать содержимое файла, используя средства NIO до
JDK 7, откройте сначала файл при помощи класса F i l e l n p u t S t r e a m . Затем получите канал к этому файлу при вызове метода g e t C h a n n e l () для объекта файла Зак 3030


6 7 Часть II. Библиотека После этого сопоставьте канал с буфером при вызове метода та р () объекта класса
F i le C h a n n e l . Метод та р () работает, как описано ранее.
Следующая программа — это предыдущий пример, переделанный так, чтобы для сопоставления файла использбвались только средства до JDK 7.
// Использование сопоставления для чтения файла. Версия до JDK 7.
import java.io.*;
import java.nio.*;
import java.n i o .channels.*;
public class MappedChannelRead {
public static void main(String a r g s []) {
Filelnputstream fin = null;
FileChannel fChan = null;
long fSize;
MappedByteBuffer mBuf;
try {
// Сначала открыть файл для ввода
fin = new Filelnputstream("tes t .txt");
// Затем получить канал к этому файлу
fChan = f I n .getChannel();
// Получить размер файла
fSize = fChan.s i z e ();
// Теперь сопоставить файл с буфером = fChan.map(FileChannel.MapMode.READ_ONLY,
0, fSize);
// Читать и отображать байты из буфера
for(int i=0; i < fSize; i
+
+)
System.o u t .p r i n t ((char)m B u f .g e t ());
} catch (IOException e) {
System.out.println("I/O Error " + e ) ;
} finally {
try {
if(fChan != null) fChan.c l o s e (); // закрыть канал
} c a t c h (IOException e) {
System.out.println("Error Closing Channel.");
}
try {
if (fin !
= null) fln.closeO; // закрыть файл
} c a t c h (IOException e) {
System.out.println("Error Closing В программе файл открывается при помощи конструктора класса F i l e ­
l n p u t s t r e a m , а ссылка на этот объект присваивается объекту f i n . Канал, подключенный к файлу, создается при вызове метода g e tC h a n n e l () объекта f i n . Затем выясняется размер файла. Далее, при вызове метода та р ( ), весь файл сопоставляется с областью в памяти, а ссылка на этот буфер сохраняется в объекте mBuf. Байты из буфера mBuf читаются при вызове метода g e t (Запись в файл до JDK В этом разделе два предыдущих примера канального вывода в файл переделаны так, чтобы использовались только средства до JDK 7. В первом примере выполня-
Глава 20. Исследование N10
6 7 5
ется запись в файл при резервировании буфера вручную и последующем явном выполнении операций записи. Во втором примере используется сопоставление файла, автоматизирующее процесс. В обоих случаях ни интерфейс
P a t h , ни оператор t r y - с - ресурсами не применяются, поскольку их не было в Java до JDK При использовании версий Java до JDK 7, для записи в файл применяется канал и зарезервированный вручную буфер при предварительном открытии файла для вывода. Для этого создается объект класса
F i l e O u t p u t S t r e a m , как описано в главе 19. Затем вы получите канал к файлу при вызове метода g e t C h a n n e l
() и зарезервируете байтовый буфер при вызове метода a l l o c a t e ( )
, как описано в предыдущем разделе. Далее поместите данные, которые хотите записать, в этот буфер и вызовите метод w r i t e
() канала. Следующая программа демонстрирует эту процедуру. Она записывает алфавит в файл по имени t e s t . t x t .
// Запись в файл с использованием N10. Версия до JDK 7.
import java.io.*;
import java.nio.*;
import java.n i o .channels.*;
public class ExplicitChannelWrite {
public static void main(String a r g s []) {
FileOutputStream fOut = null;
FileChannel fChan = null;
ByteBuffer mBuf;
try {
// Сначала открыть файл для вывода
fOut = new FileOutputStream("tes t .txt");
// Затем получить канал к файлу для вывода
fChan = fOut.getChannel();
// Создать буфер = ByteBuffer.allocate(26);
// Записать несколько байтов в буфер
for(int i=0; i<26; i
+
+ )
m B u f .p u t ((byte) (1
A 1
+ i));
// Подготовить буфер для записи
m B u f .rewind();
// Запись буфера в выходной файл
fChan.write(mBuf);
} catch (IOException e) {
System.out.println("I/O Error " + e ) ;
} finally {
try {
if(fChan != null) fChan.c l o s e (); // закрыть канал
} c a t c h (IOException e) {
System.out.println("Error Closing Channel.");
}
try {
if(fOut != null) fOut.c l o s e (); // закрыть файл
} c a t c h (IOException e) {
System.out.println("Error Closing File.");
}
}
}
}

6 7 6 Часть II. Библиотека Вызов метода r e w in d () объекта mBuf необходим для возвращения текущей позиции буфера mBuf в нуль после записи данных. Помните, что каждый вызов метода p u t () перемещает текущую позицию. Поэтому прежде, чем вызвать метод w r i t e ( ) , необходимо установить текущую позицию в начало буфера. В противном случае метод w r i t e () посчитает, что никаких данных в буфере нет.
При использовании версий Java до JDK 7, для записи в файл выполняется сопоставление файла с буфером следующим образом. Сначала откройте файл для операций чтения и записи при создании объекта класса R andom A ccessF ile. Для файла необходимо разрешение на чтение и запись. Затем сопоставьте этот файл с буфером при вызове метода та р () данного объекта. Далее запишите данные в буфер. Поскольку буфер сопоставлен с файлом, любые изменения в этом буфере автоматически отражаются в файле. Таким образом, никаких явных операций записи в канал не нужно.
Вот приведенная выше программа, переделанная для использования сопоставления файла Запись в сопоставленный файл. Версия до JDK 7.

import java.io.*;
import java.nio.*;
import java.n i o .channels.*;
public class MappedChannelWrite {
public static void main(String a r g s []) {
RandomAccessFile fOut = null;
FileChannel fChan = null;
ByteBuffer mBuf;
try {
fOut = new RandomAccessFile("te s t .txt", "rw");
// Затем получить канал к этому файлу
fChan = fOut.getChannel();
// Затем сопоставить файл с буфером = fChan.map(FileChannel.MapMode.READ_WRITE, 0, 26);
// Записать несколько байтов в буфер
for(int i=0; i<26; i
+
+)
m Buf.put((byte)(’A' + i));
} catch (IOException e) {
System.out.println("I/O Error " + e ) ;
} finally {
try {
if(fChan != null) fChan.c l o s e (); // закрыть канал
} c a tch(IOException e) {
System.out.println("Error Closing Channel.");
}
try {
if(fOut != null) fOut.cl o s e (); // закрыть файл
} c a t c h (IOException e) {
System.out.println("Error Closing Как можно заметить, здесь нет никаких явных операций записи непосредственно в канал. Поскольку буфер mBuf сопоставляется с файлом, изменения в буфере автоматически отражаются в основном файле

1   ...   57   58   59   60   61   62   63   64   ...   90


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