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

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


Скачать 1.93 Mb.
НазваниеJava io. Ключевым понятием здесь является понятие потока
Дата03.07.2022
Размер1.93 Mb.
Формат файлаdoc
Имя файлаОтветы на вопросы по ревью 4.doc
ТипДокументы
#623608
страница15 из 39
1   ...   11   12   13   14   15   16   17   18   ...   39

Почему метод read класса InputStream возвращает int, а не byte


Попробуйте выполнить такой код:

byte myByte = -3; // 11111101
byte[] myArray = {myByte};

InputStream in = new ByteArrayInputStream(myArray);
int myInt = in.read();

System.out.println(myInt); // 253

В консоль выводится 253, а не -3.

Почему так происходит?

Тип данных int в Java является дополненнным до двух целым числом и использует 32 бита вместо 8.

В 32х битном виде число 253 будет:

00000000000000000000000011111101

т. е. метод read() возвращает не само значение byte, а его представление в 32х битном виде.


Как хранятся значения в int в byte


| число | 32 bit | 8 bit |

----- -------------------------------- --------

| . . | . . . . . . . . . . . . . . . . |

| . . | . . . . . . . . . . . . . . . . |

| -128 | 11111111111111111111111110000000 | 10000000 |

| -127 | 11111111111111111111111110000001 | 10000001 |

| -126 | 11111111111111111111111110000010 | 10000010 |

| -125 | 11111111111111111111111110000011 | 10000011 |

| . . | . . . . . . . . . . . . . . . . | . . . . |

| . . | . . . . . . . . . . . . . . . . | . . . . |

| -2 | 11111111111111111111111111111110 | 11111110 |

| -1 | 11111111111111111111111111111111 | 11111111 |

| 0 | 00000000000000000000000000000000 | 00000000 |

| 1 | 00000000000000000000000000000001 | 00000001 |

| 2 | 00000000000000000000000000000010 | 00000010 |

| . . | . . . . . . . . . . . . . . . . | . . . . |

| . . | . . . . . . . . . . . . . . . . | . . . . |

| 125 | 00000000000000000000000001111101 | 01111101 |

| 126 | 00000000000000000000000001111110 | 01111110 |

| 127 | 00000000000000000000000001111111 | 01111111 |

| . . | . . . . . . . . . . . . . . . . |

| . . | . . . . . . . . . . . . . . . . |

Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.


Что происходит с числом byte в методе read


Чтобы получить представление byte в int в методе read() используется побитовое «И» c числом 255, т. е. убираем лидирующие единицы.

| число | 32 bit |

----- --------------------------------

| -3 | 11111111111111111111111111111101 |

И

| 255 | 00000000000000000000000011111111 |

=

| 253 | 00000000000000000000000011111101 |

Чтобы из представления получить обратно значение byte в int, нужно выполнить обратную операцию побитовое «ИЛИ» c числом -256, т. е. добавляем лидирующие единицы.

| число | 32 bit |

----- --------------------------------

| 253 | 00000000000000000000000011111101 |

ИЛИ

| -256 | 11111111111111111111111100000000 |

=

| -3 | 11111111111111111111111111111101 |


Что происходит с числом byte == -1 в методе read()


То же самое: убираем лидирующие единицы.

| число | 32 bit |

----- --------------------------------

| -1 | 11111111111111111111111111111111 |

И

| 255 | 00000000000000000000000011111111 |

=

| 255 | 00000000000000000000000011111111 |


5) Как создать файл на компьютере с помощью java.

Класс File, определенный в пакете java.io, не работает напрямую с потоками. Его задачей является управление информацией о файлах и каталогах. Хотя на уровне операционной системы файлы и каталоги отличаются, но в Java они описываются одним классом File.

В зависимости от того, что должен представлять объект File - файл или каталог, мы можем использовать один из конструкторов для создания объекта:

1

2

3

File(String путь_к_каталогу)

File(String путь_к_каталогу, String имя_файла)

File(File каталог, String имя_файла)

Например:

1

2

3

4

5

// создаем объект File для каталога

File dir1 = new File("C://SomeDir");

// создаем объекты для файлов, которые находятся в каталоге

File file1 = new File("C://SomeDir", "Hello.txt");

File file2 = new File(dir1, "Hello2.txt");

Класс File имеет ряд методов, которые позволяют управлять файлами и каталогами. Рассмотрим некоторые из них:

  • boolean createNewFile(): создает новый файл по пути, который передан в конструктор. В случае удачного создания возвращает true, иначе false

  • boolean delete(): удаляет каталог или файл по пути, который передан в конструктор. При удачном удалении возвращает true.

  • boolean exists(): проверяет, существует ли по указанному в конструкторе пути файл или каталог. И если файл или каталог существует, то возвращает true, иначе возвращает false

  • String getAbsolutePath(): возвращает абсолютный путь для пути, переданного в конструктор объекта

  • String getName(): возвращает краткое имя файла или каталога

  • String getParent(): возвращает имя родительского каталога

  • boolean isDirectory(): возвращает значение true, если по указанному пути располагается каталог

  • boolean isFile(): возвращает значение true, если по указанному пути находится файл

  • boolean isHidden(): возвращает значение true, если каталог или файл являются скрытыми

  • long length(): возвращает размер файла в байтах

  • long lastModified(): возвращает время последнего изменения файла или каталога. Значение представляет количество миллисекунд, прошедших с начала эпохи Unix

  • String[] list(): возвращает массив файлов и подкаталогов, которые находятся в определенном каталоге

  • File[] listFiles(): возвращает массив файлов и подкаталогов, которые находятся в определенном каталоге

  • boolean mkdir(): создает новый каталог и при удачном создании возвращает значение true

  • boolean renameTo(File dest): переименовывает файл или каталог



Работа с каталогами


Если объект File представляет каталог, то его метод isDirectory() возвращает true. И поэтому мы можем получить его содержимое - вложенные подкаталоги и файлы с помощью методов list() и listFiles(). Получим все подкаталоги и файлы в определенном каталоге:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

import java.io.File;

 

public class Program {

 

    public static void main(String[] args) {

         

        // определяем объект для каталога

        File dir = new File("C://SomeDir");

        // если объект представляет каталог

        if(dir.isDirectory())

        {

            // получаем все вложенные объекты в каталоге

            for(File item : dir.listFiles()){

              

                 if(item.isDirectory()){

                      

                     System.out.println(item.getName() + "  \t folder");

                 }

                 else{

                      

                     System.out.println(item.getName() + "\t file");

                 }

             }

        }

    }

}

Теперь выполним еще ряд операций с каталогами, как удаление, переименование и создание:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import java.io.File;

 

public class Program {

 

    public static void main(String[] args) {

         

        // определяем объект для каталога

        File dir = new File("C://SomeDir//NewDir");

        boolean created = dir.mkdir();

        if(created)

            System.out.println("Folder has been created");

        // переименуем каталог

        File newDir = new File("C://SomeDir//NewDirRenamed");

        dir.renameTo(newDir);

        // удалим каталог

        boolean deleted = newDir.delete();

        if(deleted)

            System.out.println("Folder has been deleted");

    }

}

Работа с файлами


Работа с файлами аналогична работе с каталога. Например, получим данные по одному из файлов и создадим еще один файл:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

import java.io.File;

import java.io.IOException;

 

public class Program {

 

    public static void main(String[] args) {

         

        // определяем объект для каталога

        File myFile = new File("C://SomeDir//notes.txt");

        System.out.println("File name: " + myFile.getName());

        System.out.println("Parent folder: " + myFile.getParent());

        if(myFile.exists())

            System.out.println("File exists");

        else

            System.out.println("File not found");

         

        System.out.println("File size: " + myFile.length());

        if(myFile.canRead())

            System.out.println("File can be read");

        else

            System.out.println("File can not be read");

         

        if(myFile.canWrite())

            System.out.println("File can be written");

        else

            System.out.println("File can not be written");

         

        // создадим новый файл

        File newFile = new File("C://SomeDir//MyFile");

        try

        {

            boolean created = newFile.createNewFile();

            if(created)

                System.out.println("File has been created");

        }

        catch(IOException ex){

             

            System.out.println(ex.getMessage());

        } 

    }

}

При создании нового файла метод createNewFile() в случае неудачи выбрасывает исключение IOException, поэтому нам надо его отлавливать, например, в блоке try...catch, как делается в примере выше.


6) Как удалить директорию с файлами.

Java не может удалять папки с данными в нем. Перед удалением папки необходимо удалить все файлы. использовать что-то вроде:

String []entries = index.list ();

for (String s: entries) {

File currentFile = new File (index.getPath (), s);

currentFile.delete ();}

тогда вы сможете удалить папку, используя index.delete ().


static void

deleteDirectory(File directory)

Deletes a directory recursively.

static boolean

deleteQuietly(File file)

Deletes a file, never throwing an exception.

static boolean

directoryContains(File directory, File child)

Determines whether the parent directory contains the child element (a file or directory).

static void

forceDelete(File file)

Deletes a file.

static void

forceDeleteOnExit(File file)

Schedules a file to be deleted when JVM exits.



  • deleteDirectory


  • public static void deleteDirectory(File directory)

throws IOException

Deletes a directory recursively.

Parameters:

directory - directory to delete

Throws:

IOException - in case deletion is unsuccessful

IllegalArgumentException - if directory does not exist or is not a directory
  • deleteQuietly


public static boolean deleteQuietly(File file)

Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.

The difference between File.delete() and this method are:

    • A directory to be deleted does not have to be empty.

    • No exceptions are thrown when a file or directory cannot be deleted.

Parameters:

file - file or directory to delete, can be null

Returns:

true if the file or directory was deleted, otherwise false

Since:

1.4

  • forceDelete


  • public static void forceDelete(File file)

throws IOException

Deletes a file. If file is a directory, delete it and all sub-directories.

The difference between File.delete() and this method are:

    • A directory to be deleted does not have to be empty.

    • You get exceptions when a file or directory cannot be deleted. (java.io.File methods returns a boolean)

Parameters:

file - file or directory to delete, must not be null

Throws:

NullPointerException - if the directory is null

FileNotFoundException - if the file was not found

IOException - in case deletion is unsuccessful
  • forceDeleteOnExit


  • public static void forceDeleteOnExit(File file)

throws IOException

Schedules a file to be deleted when JVM exits. If file is directory delete it and all sub-directories.

Parameters:

file - file or directory to delete, must not be null

Throws:

NullPointerException - if the file is null

IOException - in case deletion is unsuccessful
Это лучшее решение для Java 7+:

public static void deleteDirectory(String directoryFilePath) throws IOException

{

Path directory = Paths.get(directoryFilePath);
if (Files.exists(directory))

{

Files.walkFileTree(directory, new SimpleFileVisitor
()


{

@Override

public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException

{

Files.delete(path);

return FileVisitResult.CONTINUE;

}
@Override

public FileVisitResult postVisitDirectory(Path directory, IOException ioException) throws IOException

{

Files.delete(directory);

return FileVisitResult.CONTINUE;

}

});

}

}


7)  Что такое сериализация и десериализация.

Сериализация представляет процесс записи состояния объекта в поток, соответственно процесс извлечения или восстановления состояния объекта из потока называется десериализацией. Сериализация очень удобна, когда идет работа со сложными объектами.

Интерфейс Serializable


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

Сериализация. Класс ObjectOutputStream


Для сериализации объектов в поток используется класс ObjectOutputStream. Он записывает данные в поток.

Для создания объекта ObjectOutputStream в конструктор передается поток, в который производится запись:

1

ObjectOutputStream(OutputStream out)

Для записи данных ObjectOutputStream использует ряд методов, среди которых можно выделить следующие:

  • void close(): закрывает поток

  • void flush(): очищает буфер и сбрасывает его содержимое в выходной поток

  • void write(byte[] buf): записывает в поток массив байтов

  • void write(int val): записывает в поток один младший байт из val

  • void writeBoolean(boolean val): записывает в поток значение boolean

  • void writeByte(int val): записывает в поток один младший байт из val

  • void writeChar(int val): записывает в поток значение типа char, представленное целочисленным значением

  • void writeDouble(double val): записывает в поток значение типа double

  • void writeFloat(float val): записывает в поток значение типа float

  • void writeInt(int val): записывает целочисленное значение int

  • void writeLong(long val): записывает значение типа long

  • void writeShort(int val): записывает значение типа short

  • void writeUTF(String str): записывает в поток строку в кодировке UTF-8

  • void writeObject(Object obj): записывает в поток отдельный объект

Эти методы охватывают весь спектр данных, которые можно сериализовать.

Например, сохраним в файл один объект класса Person:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

import java.io.*;

 

public class Program {

 

    public static void main(String[] args) {

try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream

("person.dat")))

        {

            Person p = new Person("Sam", 33, 178, true);

            oos.writeObject(p);

        }

        catch(Exception ex){

             

            System.out.println(ex.getMessage());

        }

    }

}

class Person implements Serializable{

      

    private String name;

    private int age;

    private double height;

    private boolean married;

      

    Person(String n, int a, double h, boolean m){

          

        name=n;

        age=a;

        height=h;

        married=m;

    }

    String getName() {return name;}

    int getAge(){ return age;}

    double getHeight(){return height;}

    boolean getMarried(){return married;}

}

Десериализация. Класс ObjectInputStream


Класс ObjectInputStream отвечает за обратный процесс - чтение ранее сериализованных данных из потока. В конструкторе он принимает ссылку на поток ввода:

1

ObjectInputStream(InputStream in)

Функционал ObjectInputStream сосредоточен в методах, предназначенных для чтения различных типов данных. Рассмотрим основные методы этого класса:

  • void close(): закрывает поток

  • int skipBytes(int len): пропускает при чтении несколько байт, количество которых равно len

  • int available(): возвращает количество байт, доступных для чтения

  • int read(): считывает из потока один байт и возвращает его целочисленное представление

  • boolean readBoolean(): считывает из потока одно значение boolean

  • byte readByte(): считывает из потока один байт

  • char readChar(): считывает из потока один символ char

  • double readDouble(): считывает значение типа double

  • float readFloat(): считывает из потока значение типа float

  • int readInt(): считывает целочисленное значение int

  • long readLong(): считывает значение типа long

  • short readShort(): считывает значение типа short

  • String readUTF(): считывает строку в кодировке UTF-8

  • Object readObject(): считывает из потока объект

Например, извлечем выше сохраненный объект Person из файла:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import java.io.*;

 

public class Program {

 

    public static void main(String[] args) {

        

        try(ObjectInputStream ois = new ObjectInputStream

(new FileInputStream("person.dat")))

        {

            Person p=(Person)ois.readObject();

            System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge());

        }

        catch(Exception ex){

             

            System.out.println(ex.getMessage());

        }

    }

}







Теперь совместим сохранение и восстановление из файла на примере списка объектов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

import java.io.*;

import java.util.ArrayList;

  

public class Program {

     

    //@SuppressWarnings("unchecked")

    public static void main(String[] args) {

         

        String filename = "people.dat";

        // создадим список объектов, которые будем записывать

        ArrayList
people = new ArrayList
();

        people.add(new Person("Tom", 30, 175, false));

        people.add(new Person("Sam", 33, 178, true));

          

        try(ObjectOutputStream oos = new ObjectOutputStream

(new FileOutputStream(filename)))

        {

            oos.writeObject(people);

            System.out.println("File has been written");

        }

        catch(Exception ex){

              

            System.out.println(ex.getMessage());

        }

          

        // десериализация в новый список

        ArrayList
newPeople= new ArrayList
();

        try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)))

        {

             

            newPeople=((ArrayList
)ois.readObject());

        }

        catch(Exception ex){

              

            System.out.println(ex.getMessage());

        }

          

        for(Person p : newPeople)

            System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge());

    }

}

class Person implements Serializable{

      

    private String name;

    private int age;

    private double height;

    private boolean married;

      

    Person(String n, int a, double h, boolean m){

          

        name=n;

        age=a;

        height=h;

        married=m;

    }

    String getName() {return name;}

    int getAge(){ return age;}

    double getHeight(){return height;}

    boolean getMarried(){return married;}

}

Исключение данных из сериализации


По умолчанию сериализуются все переменные объекта. Однако, возможно, мы хотим, чтобы некоторые поля были исключены из сериализации. Для этого они должны быть объявлены с модификатором transient. Например, исключим из сериализации объекта Person переменные height и married:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

class Person implements Serializable{

      

    private String name;

    private int age;

    private transient double height;

    private transient boolean married;

      

    Person(String n, int a, double h, boolean m){

          

        name=n;

        age=a;

        height=h;

        married=m;

    }

    String getName() {return name;}

    int getAge(){ return age;}

    double getHeight(){return height;}

    boolean getMarried(){return married;}

}

8) Назовите несколько форматов сериализации.

  • Что такое «сериализация»?

  • Опишите процесс сериализации/десериализации с использованием Serializable.

  • Как изменить стандартное поведение сериализации/десериализации?

  • Как исключить поля из сериализации?

  • Что обозначает ключевое слово transient?

  • Какое влияние оказывают на сериализуемость модификаторы полей static и final

  • Как не допустить сериализацию?

  • Как создать собственный протокол сериализации?

  • Какая роль поля serialVersionUID в сериализации?

  • Когда стоит изменять значение поля serialVersionUID?

  • В чем проблема сериализации Singleton?

  • Какие существуют способы контроля за значениями десериализованного объекта
1   ...   11   12   13   14   15   16   17   18   ...   39


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