page prйcйdantetable des matiиrespage suivante

Потоков вход-изход

 Обектно-ориентираното проектиране използва потоци (stream) за входно-изходни операции:


 
 

Съществуват голямо количество (дори прекалено много) класове за реализация на входно-изходните операции. Класовете най-общо могат да се разделят на две групи - класове поддържащи стария подход въведен  Java 1.0, базиран на  потоци от байтове и новия подход въведен от  Java 1.1 базиран  на unicode символи.
 

Класове за четене и запис върху физически носители (ниско ниво)

Java 1.0 класове Java 1.1 класове Коментар
InputStream Reader Базов клас за вход (четене)
OutputStream Writer Базов клас за изход (писане)
FileInputStream FileReader За въвеждане от файл
FileOutputStream FileWriter За извеждане във файл
StringBufferInputStream StringReader За въвеждане и извеждане на низ 
от символи
  StringWriter
ByteArrayInputStream CharArrayReader Позволява буфер от паметта да бъде 
използван във входен и изходен поток
ByteArrayOutputStream CharArrayWriter
PipedInputStream PipedReader Използва се в многонишковото 
програмиране
PipedOutputStream PipedWriter

Повечето класове които работят с потоци от байтове  са производни на един от абстрактните класове InputStream и OutputStream.  Методите, които могат да се използват върху такива потоци за четене са:

методите за записване са:

 

 Повечето класове които работят с потоци от символи са производни на един от абстрактните класове Reader и Writer. Методите, които могат да се използват върху такива потоци са много подобни на предишните, като само типът на прочетените данни е различен:

Методите за запис са:


Класове за четене и запис (високо ниво, филтри)

Филтърът представлява поток, който обвива друг поток. Филтърът обработва данните преди да ги предаде. Той може да ги помести в буфер, да ги кодира ...

 

Java 1.0 класове Java 1.1 класове Коментар
FilterInputStream FilterReader абстрактни класове, базови за другите
входно-изходни класове
FilterOutputStream FilterWriter
BufferedInputStream BufferedReader Позволява readLine(), буферира 
въвеждането и извеждането
BufferedOutputStream BufferedWriter
DataInputStream DataInputStream За въвеждане и извеждане на 
примитивни типове (char, int, ...)
DataOutputStream DataOutputStream
PrintStream PrintWriter За форматиран изход
LineNumber InputStream LineNumberReader Филтър, който позволява да се следи
номера на линията на текстови файл
(getLineNumber())
StreamTokenizer StreamTokenizer Преобразува входния поток в "tokens"
(различава идентификатори, числа...)
PushBackInputStream PushBackReader Връща прочетен символ в потока
SequenceInputStream SequenceInputStream Логическо свързване на няколко 
входни потока
RandomAccessFile RandomAccessFile Позволява директен достъп чрез файлов 
указател до съдържанието на файл
 

Четене от стандартния потоков вход

пример java  ReadStdin
import java.io.*;
public class ReadStdin {
   public static void main(String arg[]) {
      try {        
         BufferedReader stdin = new BufferedReader(
                           new InputStreamReader(System.in));
         System.out.print("Enter a line: ");
         System.out.println(stdin.readLine());
         stdin.close();
       }
       catch(IOException e) {
          e.printStackTrace();
       }
  }
}
Enter a line: abrakadabra nawuhodonosor
abrakadabra nawuhodonosor

Четене от стандартния потоков вход (втори начин) - клас Scanner

Класът Scanner се намира в пакета util и осигурява прости средства за четене и преобразуване до примитивни типове данни информация от файл включително и от стандартния вход(System.in) .

Класът анализира и разделя входната информация на единици (tokens), като използва разграничител, който може да се променя но подразбиране е празен интервал.

Някои методи на класа:

тип на резултата Описание
Scanner
new Scanner(System.in)  //конструктор
 BigDecimal nextBigDecimal()
          Scans the next token of the input as a BigDecimal.
 BigInteger nextBigInteger()
          Scans the next token of the input as a BigInteger.
 BigInteger nextBigInteger(int radix)
          Scans the next token of the input as a BigInteger.
 boolean nextBoolean()
          Scans the next token of the input into a boolean value and returns that value.
 byte nextByte()
          Scans the next token of the input as a byte.
 byte nextByte(int radix)
          Scans the next token of the input as a byte.
 double nextDouble()
          Scans the next token of the input as a double.
 float nextFloat()
          Scans the next token of the input as a float.
 int nextInt()
          Scans the next token of the input as an int.
 int nextInt(int radix)
          Scans the next token of the input as an int.
 String nextLine()
          Advances this scanner past the current line and returns the input that was skipped.
 long nextLong()
          Scans the next token of the input as a long.
 long nextLong(int radix)
          Scans the next token of the input as a long.
 short nextShort()
          Scans the next token of the input as a short.
 short nextShort(int radix)
          Scans the next token of the input as a short.
  
Пример:
java StdInputTest
import java.util.*;

public class StdInputTest

   public static void main(String[] args)
   { 
      Scanner in = new Scanner(System.in);

      // get first input
      System.out.print("What is your name? ");
      String name = in.nextLine();

      // get second input
      System.out.print("How old are you? ");
      int age = in.nextInt();

      // display output on console
      System.out.println("Hello, " + name + ". Next year, you'll be " + (age + 1));
   }
}
What is your name? Pijo
How old are you? 21
Hello, Pijo. Next year, you'll be 22


Четене от стандартния потоков вход (трети начин) клас JOptionPane
използва изкачащ диалогов прозорец

 import javax.swing.JOptionPane;

 public class TestInp {

    public static void main( String[] args ){
       String name = "",s_age="";
       int age;
       name=JOptionPane.showInputDialog("Please enter your name");
       s_age=JOptionPane.showInputDialog("How old are You?");
       age=Integer.parseInt(s_age);
       String msg = "Hello " + name + " next year,you'll be " + (age + 1);
   
       JOptionPane.showMessageDialog(null, msg);
    }
}

JOptionPane.showInputDialog() - връща низ като резултат



Поток от байтове

exemple
import java.io.*;
   public class ByteCopy {
      public static void main(String arg[]) {
         int bt;
         try {

            System.out.print("file to be copied:");
            BufferedReader stdin = new BufferedReader(new  InputStreamReader(System.in));
            String s =stdin.readLine();

            System.out.print("new file: ");           
            String sn= stdin.readLine();
            
            System.out.println("copy the file "+s+" in the file "+sn);
            
            FileInputStream fi = new FileInputStream(s);
            FileOutputStream fo = new FileOutputStream(sn);


            while((bt= fi.read())!=-1)fo.write(bt);

            stdin.close();
            fi.close();
            fo.close();
            System.out.println("created");
         }
         catch(IOException e) {
         System.out.println("Error:"+e);;
      }
   }
}

Буферирано  четене и запис

example
import java.io.*;

public class FCopyArr {
    public static void main(String arg[]) throws IOException{
        byte bt[] = new byte[2048];
        int len;
        
        System.out.print ("file to be copied:");
        // lecture du flot d'entree standart
        BufferedReader stdin = new BufferedReader(new  InputStreamReader(System.in));
        String fns =stdin.readLine();

        System.out.print("new file: ");           
        String fnd= stdin.readLine();

        System.out.println("copy the file "+fns+" in the file "+fnd);
        FileInputStream fi = null;
        FileOutputStream fo = null;
        try {
            fi = new FileInputStream(fns);
            fo = new FileOutputStream(fnd);
            while((len = fi.read(bt))!=-1){
                fo.write(bt,0,len);
            }
            System.out.println("file "+fns+" is copied as "+fnd);
        }
        catch(FileNotFoundException ex){
            if(fi== null)System.out.println("The file "+fns+" does not exist");
            else System.out.println("not possible to create "+fnd);
        }
        finally{
            if(fi != null)fi.close();
            if(fo != null)fo.close();
        }
    }
}

Забележка: FileNotFoundException наследява IOException


Поток от символи 

import java.io.*;
public class FcharCopy {
    public static void main(String arg[]) throws IOException{
        int bt;
        if(arg.length!=2){
            System.out.println("Usage: FCopy fileSource fileDestination");
            return;
        }
        String fns = arg[0], fnd = arg[1];
        System.out.println("copy the file "+fns+" in the file "+fnd+"\n");
        FileReader fi = null;
        FileWriter fo = null;
        try {
            fi = new FileReader(fns);
            fo = new FileWriter(fnd);
            while((bt = fi.read())!=-1){
                fo.write(bt);
                System.out.print((char)bt);
            }
            System.out.println("\n\nfile "+fns+" is copied as "+fnd);
        }
        catch(FileNotFoundException ex){
            System.out.println("The file "+fns+" does not exist");
        }
        finally{
            if(fi != null)fi.close();
            if(fo != null)fo.close();
        }
    }
}


Поток от линии - класове филтри

import java.io.*;
public class LineCopy {
    public static void main(String arg[]) throws IOException{
        String line = null;        
        String fns=null, fnd=null;
        BufferedReader fi = null;
        PrintWriter fo = null;
        if(arg.length!=2){
            System.out.println("Usage: FCopy fileSource fileDestination");
            return;
        }
        fns = arg[0]; fnd = arg[1];
        System.out.println("copy the file "+fns+" in the file "+fnd+"\n");
        try {
            fi = new BufferedReader(new FileReader(fns));
            fo = new PrintWriter(new FileWriter(fnd));
            while((line = fi.readLine())!= null){
                System.out.println(line);
                fo.println(line);
            }
            System.out.println("\n\nfile "+fns+" is copied as "+fnd);
        }
        catch(FileNotFoundException ex){
            System.out.println("The file "+fns+" does not exist");
            System.out.println("or the file "+fnd+" can not be created");
        }
        finally{
            if(fi != null)fi.close();
            if(fo != null)fo.close();
        }
    }
}

Забележки:

Класът "BufferedReader"  използва буфер за четене и позволява използването на "readLine()


Класът File

Извеждане на съдържанието на една директория.
 
Пример Резултат
import java.io.*;
/** print a list of file names in the directory */

public class FileListe{
   public static void main(String args[]) {
      try{
         File path = new File(".");
         String[] list = path.list();
         for(int i = 0; i < list.length; i++)
          System.out.println(list[i]);
      } catch (Exception e) {
         e.printStackTrace();
      }
    }
}

Stdin.java
io.html
read_stream.gif
write_stream.gif
io_bases_classes.gif
io_classes.gif
stdin.class
FileListe.java
FileInfo.java
FileListe.class
FileInfo.class

Информация за параметрите на файл
 
Пример  При стартиране с:
java FileInfo FileInfo.java
import java.io.*;
import java.util.*;
/**print  the file charcteristics */

public class FileInfo{
   public static void main(String args[]) {
      if(args.length == 0){
         System.out.println(
                "Usage FileInfo <FilePath> ");
         return;
      }

      File f = new File(args[0]);
      System.out.println(
            " Abs path: " + f.getAbsolutePath() +
            "\n write: " + f.canWrite() +
            "\n read: " + f.canRead() +
            "\n Name: " + f.getName() +
            "\n Length: " + f.length() +
            "\n Parent " + f.getParent() +
            "\n Path: " + f.getPath() +
            "\n Modif: " + 
                            new Date(f.lastModified()));
      if(f.isFile())
            System.out.println("fichier");
      else if(f.isDirectory())
            System.out.println("repertoire");
   }
}

Abs path: E:\My_Documents\JAVA\CoursJava(my)\io\FileInfo.java
 write: true
 read: true
 Name: FileInfo.java
 Length: 855
 Parent null
 Path: FileInfo.java
 Modif: Tue May 14 10:30:44 GMT+03:00 2002
fichier

 

Създаване, преименуване и изтриване на файлове

 
Пример Резултат
import java.io.*;

public class FichierManip{
   public static void main(String args[]) {
      File nouveau = new File("Test.txt");
      File change = new File("Test_change.txt");
      dir();
      try{
         nouveau.createNewFile();
      }catch (IOException e) {e.printStackTrace();}
      dir();
      nouveau.renameTo(change);
      dir();
      change.delete();
      dir();
      nouveau.mkdirs();
      dir();
      nouveau.delete();
      dir(); 
   }

   public static void dir() {
      try{
         File repert = new File(".");
         String[] liste = repert.list();
         for(int i = 0; i< liste.length; i++)
            System.out.println(liste[i]);
         System.out.println("\n");
      } catch (Exception e) { e.printStackTrace();  }
   }
}

FichierManip.class

FichierManip.class
Test.txt

FichierManip.class
Test_change.txt

FichierManip.class

FichierManip.class
Test.txt

FichierManip.class

 


 

Устойчивост (Persistence) на обектите. Сериализация на обекти

Сериализация - запис на обекти в даден поток 

Сериализацията се използва за запазване на обектите (persist) във файл, база от данни, мрежа, друг процес или друга система. Сериализацията преобразува обектите в подреден, последователен поток от байтове ( "flattening") .  Този поток може да бъде прочетен по-късно за реконструиране на оригиналния обект (deserialization).

Сериализацият не се извършва за  transient или static полета. Маркирането на полето   transient не позволява записването му в потока и възстановяването му при десериализация.  Използва се за маркиране на временни променливи или променливи съдъжащи локална информация като времеви данни или идентификатори на процеси.

Само обекти които наследяват  java.io.Serializable  интерфейс могат дъдат сериализирани.

Класът ObjectOutputStream
        клас от пакетът java.io - съдържа методи за "сериализация" на обекти,масиви и базови типове.
        важни методи:
             writeObject()                    //записва обектите
             defaultWriteObject()        //викан от writeObject() за запис на компоненти

Класът ObjectInputStream
        клас от пакетът java.io - съдържа методи за "де-сериализация" на обекти,масиви и базови типове.
        важни методи:
             readObject()                    //чете обектите
             defaultReadObject()        //викан от readObject() за четене на компоненти

Всички методи могат да предизвикат IOException
 
 Информация запазвана при сериализацията - необходимата за реконструиране на състоянието на обекта
    - Запазват се само не-статичните данни
    - Методите не са част от тази информация
    - Запазва се информация за класа
    - Не се интересува от видимостта на компонентите

Конструктори (например за файл save.ser в текущата директория)

ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("save.ser"));
ObjectOutputStream oos =  new ObjectOutputStream (new FileOutputStream ("save.ser"));

Пример 

import java.io.*;

public class PersonSr implements Serializable{
         static int num=0;
         String
name;
         String
id;
         PersonSr(){
                name = "student "+ ++num;
                id = (int)(Math.random()*3999)+1111+"";
         }
}

public class StudentSr extends PersonSr{
         int notes[];
         StudentSr(){
               notes = new int [5];
                for(int i =0;i<notes.length;i++){
                      notes[i]=(int)(Math.random()*5)+2;
                }
         }
         public
 String toString(){
            String
 rez;
            rez = "name:"+name+"\tid:"+id+"\tnotes:";
             for(int i=0;i<notes.length;i++){
                      rez += "\t"+notes[i];
             }
             return rez;     
        
 }
}


Запис

 import java.io.*;

public
 class StudWr {
         public
 static void main(String arg[]) throws IOException{
                ObjectOutputStream oos = null;
                StudentSr s;
                try{
                      oos = new ObjectOutputStream (
                            new FileOutputStream ("save.ser"));
                      for(int i=0;i<9;i++){
                            s =new StudentSr();
                            
System.out.println(""+s);
                            oos.writeObject(s);
                      }
                }
                finally{
                      oos.close();
                }
         }
}

Résultat:

name:student 1      id:4236     notes: 3    4    5    6    4

name:student 2      id:4051     notes: 2    6    4    4    4

name:student 3      id:2745     notes: 6    3    5    3    4

name:student 4      id:2550     notes: 4    2    2    4    6

name:student 5      id:3783     notes: 6    2    6    4    2

name:student 6      id:1677     notes: 2    4    5    4    6

name:student 7      id:1378     notes: 5    2    2    5    4

name:student 8      id:2112     notes: 2    5    4    6    5

name:student 9      id:3111     notes: 5    2    6    3    6

 


Десериализация

import java.io.*;

public class StudRd {
         public
 static void main(String[] arg)throws
                       IOException,ClassNotFoundException{

                ObjectInputStream ois = null;
                StudentSr s;
                int n=0, nf=0;
                try{
                      ois = new ObjectInputStream (new FileInputStream ("save.ser"));

                      for(;;){
                            s= (StudentSr)ois.readObject();
                            n++;
                            if
(average(s)>=4){
                                   System.out.print(""+s);
                                   System.out.println("\thas average "+ average(s));
                                   nf++;
                            }
                      }
                }
                catch(EOFException ex){
                      System.out.println("printed "+nf+" students, found total "+n+" students");
                }
                finally{
                      ois.close();
                }
         }
         public
 static double average(StudentSr s){
                double sum;
                int i;
                for(sum=i=0;i<s.notes.length;i++){
                      sum+=s.notes[i];
                }
                return sum/s.notes.length;
         }
}

Резултат:

name:student 1      id:4236     notes: 3    4    5    6    4    has average 4.4
name:student 2      id:4051     notes: 2    6    4    4    4    has average 4.0
name:student 3      id:2745     notes: 6    3    5    3    4    has average 4.2
name:student 5      id:3783     notes: 6    2    6    4    2    has average 4.0
name:student 6      id:1677     notes: 2    4    5    4    6    has average 4.2
name:student 8      id:2112     notes: 2    5    4    6    5    has average 4.4
name:student 9      id:3111     notes: 5    2    6    3    6    has average 4.4
printed 7 students, found total 9 students

 
Ключова дума   transient

 Пример 
class MyClass implements Serializable {
    transient Thread thread;  //Skip serialization of the transient field
    transient String fieldIdontwantSerialization;
         // Serialize the rest of the fields
    int data;
    String x;
         // More code
}

Изисквания за сериализация

● За да може един обект да е "serializable":класът му трябва да наследява интерфейсът Serializable. Това е "marker interface"
● Сериализируемостта се наследява и може да се сложи само веднъж в дървовидната йерархия


Не сериализируеми обекти
● Повечето  Java класове са сериализируеми
● Обектите от някой системни класове например Thread не са.
● При опит за сериализиране на такъв обект се генерира изключение NotSerializableException

Още един пример

NIO2, канали,  файлове с директен достъп


класa Path

 Въведен в Java 7  за да замести клса File. Различен за различни операционни системи. Не е задължително пътят реално да съществува.

Създаване:

Path path = Paths.get("Test.txt");                         // в текущата директория
Path path = Paths.get("D:\\data\\Test.txt");            // Windows
Path path = Paths.get("/home/data/Test.txt");            //  Unix

Синттаксически операции - Пример 

import java.nio.file.Path;
import java.nio.file.Paths;
public class PathInf {
    public static void main(String arg[]){
        Path absPath = Paths.get("D:\\iv\\dt\\sys\\Test.txt");  //windows файлова система
        System.out.format("absolute Path %n");
        System.out.format("toString: %s%n",absPath.toString());
        System.out.format("getFileName: %s%n", absPath.getFileName());
        System.out.format("getNameCount: %d%n",absPath.getNameCount());
        for(int i=0; ;i++){
            try{
                System.out.format("getName(%d): %s%n", i,absPath.getName(i));
            }catch(IllegalArgumentException ex){
                System.out.format("no more names %n");
                break;
            }
        }
        System.out.format("subpath(0,2): %s%n",absPath.subpath(0,2));
        System.out.format("getParent: %s%n",absPath.getParent());
        System.out.format("getRoot: %s%n",absPath.getRoot());
        Path relPath = Paths.get("dt\\sys\\Test.txt");
        System.out.format("%n relative Path %n");
        System.out.format("toString: %s%n",relPath.toString());
        System.out.format("getFileName: %s%n", relPath.getFileName());
        System.out.format("getName(0): %s%n", relPath.getName(0));
        System.out.format("getNameCount: %d%n",relPath.getNameCount());
        for (Path name : relPath) {
            System.out.format("Name: %s%n",name);
        }
        System.out.format("subpath(0,2): %s%n",relPath.subpath(0,2));
        System.out.format("getParent: %s%n",relPath.getParent());
        System.out.format("getRoot: %s%n",relPath.getRoot());
    }
}
absolute Path
toString: D:\iv\dt\sys\Test.txt
getFileName: Test.txt
getNameCount: 4
getName(0): iv
getName(1): dt
getName(2): sys
getName(3): Test.txt
no more names
subpath(0,2): iv\dt
getParent: D:\iv\dt\sys
getRoot: D:\

 relative Path
toString: \dt\sys\Test.txt
getFileName: Test.txt
getName(0): dt
getNameCount: 3
Name(0): dt
Name(1): sys
Name(2): Test.txt
subpath(0,2): dt\sys
getParent: \dt\sys
getRoot: \

Буфери

Главната разлика между между използването на канали и потоковия вход изход е че обмена на информация е базиран върху блокове. Втората разлика е, че един канал може да бъде използван както за вход така и за изход.

Буферът прдставлява масив. Най-често е използван масив от байтове -
ByteBuffer, но могат да се използват и други производни на класа  Buffer   -  CharBuffer, IntBuffer, ShortBuffer, LongBuffer, FloatBuffer и DoubleBuffer.

Всеки буфер - 4 параметра:
Създаване:
При въвеждане - празни буфери:

     ByteBuffer buffer1 = ByteBuffer.allocate(100);
Може да се получи референция на масив с
     byte[] data1 = buffer1.array();

При извеждане:
    int[] data = {1, 3, 2, 4, 23, 53, -9, 67};
    IntBuffer buffer = IntBuffer.wrap(data);

Достъп -  ByteBuffer  притежава методите  get() и put() , които могат да се използват с най-различни параметри напр.
    public ByteBuffer get(byte[] dst)
    public ByteBuffer get(byte[] dst, int offset, int length)


Канали
    Интерфейсите ReadableByteChannel и WritableByteChannel  се наследяват от каналите за вход и изход. Един канал може да наследи и двата интерфейса.
     Интерфейсът
SeekableByteChannel е въведен в Java 7 и осигурява директен достъп чрез параметъра  position на канала.
•    position() – връща текущата позиция;
•    position(long) – сменя позицията;
•    truncate(long) – изрязва файла до зададената позиция;
•    read(ByteBuffer) – чете информацията в буфера;
•    size() – връща броя на байтовете във файла.

     Следващият пример чете информацията в началото, в средата и в края на файла
Test.txt. Буферът е фиксиран на 5 байта. Методът flip() подготвя буфера за писане.

import java.io.*;
import java.nio.*;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.util.EnumSet;

public class RafRead {
    public static void main(String[] args) {
        int bufLen=5;
        Path path = Paths.get("Test.txt");
        ByteBuffer buf = ByteBuffer.allocate(bufLen);
        String encoding = System.getProperty("file.encoding");
        try (SeekableByteChannel sbc = (Files.newByteChannel(
                path, EnumSet.of(StandardOpenOption.READ)))) {
            System.out.println("the size of the file is "+sbc.size());
            sbc.position(0);
            System.out.println("\nReading "+bufLen+" character from position: "
                    + sbc.position());
            do{
                sbc.read(buf);
            }while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.rewind();
            // позициониране в средата
            sbc.position(sbc.size() / 2);
            System.out.println("\nReading "+bufLen+" character from position: "
                    + sbc.position());
            do{
                sbc.read(buf);
            }while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.rewind();
            // позициониране в края
            sbc.position(sbc.size() - bufLen);
            System.out.println("\nReading "+bufLen+" character from position: "
                    + sbc.position());
            do{
                sbc.read(buf);
            }while(buf.hasRemaining());
            buf.flip();
            System.out.print(Charset.forName(encoding).decode(buf));
            buf.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

Примера чете първите 10 байта от файла  Test.txt и ги записва в края на файла.

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
public class RafRW {
    public static void main(String[] args) {
        Path path = Paths.get("Test.txt");
        ByteBuffer bf = ByteBuffer.allocate(10);  
        try (SeekableByteChannel sbc = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))) {
          
            sbc.position(0);
            do {
                sbc.read(bf);
            } while (bf.hasRemaining());
            bf.flip();
            sbc.position(sbc.size());
            while (bf.hasRemaining()) {
                sbc.write(bf);
            }
            bf.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

page prйcйdantetable des matiиrespage suivante