User Tools

Site Tools


java:byte_streams_to_data

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
java:byte_streams_to_data [2020/03/04 14:38] gthanosjava:byte_streams_to_data [Unknown date] (current) – external edit (Unknown date) 127.0.0.1
Line 1: Line 1:
-====== Μετασχηματισμός των ροών δεδομένων σε τύπους δεδομένων ======+====== Μετασχηματισμός των ροών δυαδικών δεδομένων σε βασικούς τύπους δεδομένων ======
  
-Ο προηγούμενος κώδικας δουλεύει εξαιρετικά με ροές από bytes, στην πραγματικότητα όμως τα δεδομένα που θέλουμε να αποθηκεύσουμε ή να διαβάσουμε μπορεί να είναι ακέραιοι, αριθμοί κινητής υποδιαστολής κλπ. Προκειμένου να μπορέσουμε να διαβάσουμε ή να γράψουμε μορφές πληροφορίας που απαιτούν περισσότερα του ενός bytes έρχεται σε βοήθεια η κλάση [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]]. Η κλάση αυτή παρέχει ένα buffer μέσω του οποίου μπορούμε να γράψουμε ή να διαβάσουμε σύνθετους τύπους πληροφορίας. +Ο προηγούμενος κώδικας δουλεύει εξαιρετικά με ροές από bytes, στην πραγματικότητα όμως τα δεδομένα που θέλουμε να αποθηκεύσουμε ή να διαβάσουμε μπορεί να είναι ακέραιοι, αριθμοί κινητής υποδιαστολής ή άλλοι βασικοί τύποι δεδομένων. Προκειμένου να μπορέσουμε να διαβάσουμε ή να γράψουμε μορφές πληροφορίας που απαιτούν περισσότερα του ενός bytes έρχεται σε βοήθεια η κλάση [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]]. Η κλάση αυτή παρέχει ένα buffer μέσω του οποίου μπορούμε να γράψουμε ή να διαβάσουμε σύνθετους τύπους πληροφορίας. 
  
 Για παράδειγμα, ας υποθέσουμε ότι έχουμε μία σειρά από δεδομένα που θέλουμε να γράψουμε με συγκεκριμένη σειρά σε ένα αρχείο, όλα σε δυαδική μορφή. Προκειμένου να το επιτύχουμε θα πρέπει να κάνουμε τα εξής:  Για παράδειγμα, ας υποθέσουμε ότι έχουμε μία σειρά από δεδομένα που θέλουμε να γράψουμε με συγκεκριμένη σειρά σε ένα αρχείο, όλα σε δυαδική μορφή. Προκειμένου να το επιτύχουμε θα πρέπει να κάνουμε τα εξής: 
Line 9: Line 9:
  
 Η διαδικασία ανάγνωσης είναι ακριβώς η αντίστροφή, δηλαδή: Η διαδικασία ανάγνωσης είναι ακριβώς η αντίστροφή, δηλαδή:
-  - διαβάζουμε από ένα [https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html|InputStream]] την πληροφορία σε ένα πίνακα από bytes. +  - διαβάζουμε από ένα [[https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html|InputStream]] την πληροφορία σε ένα πίνακα από bytes. 
-  - Από τον πίνακα αυτό δημιουργούμε ένα [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]].  +  - από τον πίνακα αυτό δημιουργούμε ένα [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]].  
-  - Από το [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]] εξάγουμε την πληροφορία με τη σειρά που γνωρίζουμε ότι αυτή είναι αποθηκευμένη.+  - από το [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]] εξάγουμε την πληροφορία με τη σειρά που γνωρίζουμε ότι αυτή είναι αποθηκευμένη.
  
-Το παρακάτω πρόγραμμα καλεί αρχικά τη συνάρτηση write η οποία αποθηκεύει έναν ακέραιο, ένα double, ένα χαρακτήρα (τον ελληνικό χαρακτρήρα 'Θ' (κεφαλαίο) και ένα string (το αλφαριθμητικό "Πως είσαι;") σε ένα αρχείο με όνομα **my.bin** και στη συνέχεια καλεί τη συνάρτηση read η οποια ανοίγει ένα [[https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html|FileInputStream]] για διάβασμα από το συγκεκριμένο αρχείο.+Το παρακάτω πρόγραμμα καλεί αρχικά τη συνάρτηση ''write'' η οποία χρησιμοποιεί ένα [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]] για να αποθηκεύσει έναν ακέραιο, ένα double, ένα χαρακτήρα (τον ελληνικό χαρακτρήρα 'Θ' (κεφαλαίο) και ένα string (το αλφαριθμητικό "Πως είσαι;") σε ένα αρχείο με όνομα **my.bin**. Στη συνέχεια, το πρόγραμμα καλεί τη συνάρτηση ''read'' η οποια ανοίγει ένα [[https://docs.oracle.com/javase/8/docs/api/java/io/FileInputStream.html|FileInputStream]] για διάβασμα από το συγκεκριμένο αρχείο αποθηκεύει την πληροφορία που διάβασε σε ένα byte array από αυτό δημιουργεί ένα [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|java.nio.ByteBuffer]]. Το buffer αυτό το χρησιμοποιούμε για να διαβάσουμε τα στοιχεία που αποθηκεύσαμε στο αρχείο με τη σειρά που τα βάλαμε.
  
-<code java BufferReadWriteTest.java>+<code java ByteBufferReadWriteTest.java>
 import java.nio.*; import java.nio.*;
 import java.io.*; import java.io.*;
 +import java.util.Arrays;
  
 public class ByteBufferReadWriteTest { public class ByteBufferReadWriteTest {
Line 35: Line 36:
      
   public static void main(String []args ) {   public static void main(String []args ) {
-    File file = new File("my.bin");+    File file = new File("file.bin");
     write(file);     write(file);
     read(file);     read(file);
Line 43: Line 44:
     int a = -159954;     int a = -159954;
     double b = 125.128953;     double b = 125.128953;
-    char c = 'Θ';+    char c = 'θ';
     String str = "Πώς είσαι;";     String str = "Πώς είσαι;";
          
-    ByteBuffer buffer = ByteBuffer.allocate(34);+    ByteBuffer buffer = ByteBuffer.allocate(512); 
 +    buffer.order(ByteOrder.BIG_ENDIAN);
     buffer.putInt(a);     buffer.putInt(a);
     buffer.putDouble(b);     buffer.putDouble(b);
     buffer.putChar(c);     buffer.putChar(c);
     buffer.put(str.getBytes(java.nio.charset.StandardCharsets.UTF_8));     buffer.put(str.getBytes(java.nio.charset.StandardCharsets.UTF_8));
 +    int buffer_size = buffer.position();
          
     try(FileOutputStream out = new FileOutputStream(file)) {     try(FileOutputStream out = new FileOutputStream(file)) {
       byte []array = buffer.array();       byte []array = buffer.array();
 +      array = Arrays.copyOf(array, buffer_size);
       out.write(array);       out.write(array);
       // just for debugging purposes       // just for debugging purposes
-      // print_array(array);+      //print_array(array);
     }     }
     catch(IOException ex) {     catch(IOException ex) {
Line 69: Line 73:
          
     byte array[] = new byte[512];     byte array[] = new byte[512];
-    +    int read_size;
     try(FileInputStream in = new FileInputStream(file)) {     try(FileInputStream in = new FileInputStream(file)) {
-      in.read(array);+      read_size = in.read(array); 
 +      array = Arrays.copyOf(array, read_size);
     }     }
     catch(IOException ex) {     catch(IOException ex) {
Line 77: Line 82:
     }     }
     // just for debugging purposes     // just for debugging purposes
-    // print_array(array);+    //print_array(array);
          
     ByteBuffer buffer = ByteBuffer.wrap(array);     ByteBuffer buffer = ByteBuffer.wrap(array);
 +    buffer.order(ByteOrder.BIG_ENDIAN);
     System.out.println(buffer.getInt());     System.out.println(buffer.getInt());
     System.out.println(buffer.getDouble());     System.out.println(buffer.getDouble());
-    System.out.println(buffer.getChar()); +    System.out.println("'"+buffer.getChar()+"'"); 
-    byte [] str = new byte[18]; +    int str_size = buffer.remaining(); 
-    buffer.get(str); +    byte[] bytes = new byte[str_size]; 
-    System.out.println(new String(str, java.nio.charset.StandardCharsets.UTF_8));+    buffer.get(bytes); 
 +    System.out.println(new String(bytes, java.nio.charset.StandardCharsets.UTF_8)); 
 +  } 
 +
 +</code> 
 + 
 +<WRAP tip 80% center round> 
 +H //default// υλοποίηση ενός [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|ByteBuffer]] καταχωρεί τα δεδομένα ή διαβάζει τα δεδομένα κατά big-endian. Εάν θέλετε να αλλάξετε τη σειρά καταχώρησης των δεδομένων στο buffer σε little-endian, μπορείτε να χρησιμοποιήσετε τη μέθοδο [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#order-java.nio.ByteOrder-|order]]. H μέθοδος λαμβάνει ένα αντικείμενο της κλάσης [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteOrder.html|java.nio.ByteOrder]], το οποίο είναι ένα εκ των [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteOrder.html#BIG_ENDIAN|java.nio.ByteOrder.BIG_ENDIAN]] ή [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteOrder.html#LITTLE_ENDIAN|java.nio.ByteOrder.LITTLE_ENDIAN]].  
 +Πληροφορίες για τη διαφορά μεταξύ big-endian και little-endian μπορείτε να βρείτε [[https://www.youtube.com/watch?v=seZLUbgbB7Y|στο βίντεο]]. 
 +</WRAP> 
 + 
 +<WRAP todo 80% center round> 
 +  - Αλλάξτε το παραπάνω παράδειγμα, ώστε τα δεδομένα να αποθηκεύονται κατά little-endian και όχι κατά big-endian που είναι το default.  
 +  - Βάλτε σε σχόλια τη στατική μέθοδο ''read'' και προσπαθήστε να διαβάσετε μέσα στη μέθοδο ''write'' από το buffer που μόλις γράψατε. (βοήθεια: θα χρειαστείτε τη μέθοδο //rewind// της γονικής κλάσης [[https://docs.oracle.com/javase/8/docs/api/java/nio/Buffer.html|java.nio.Buffer]]. 
 +</WRAP> 
 + 
 + 
 +====== DataInputStream & DataOutputStream ====== 
 + 
 +Στις περιπτώσεις που τα δεδομένα γνωρίζουμε ότι έχουν αποθηκευτεί κατά big-endian εναλλακτικά της χρήσης των παραπάνω κλάσεων μπορούμε να χρησιμοποιήσουμε τις απλούστερες κλάσεις [[https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html|DataInputStream]] και [[https://docs.oracle.com/javase/8/docs/api/java/io/DataOutputStream.html|DataOutputStream]]. Οι κλάσεις αυτές δημιουργούν ένα [[https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html|InputStream]] μέσω του οποίου μπορούμε να διαβάσουμε τους βασικούς τύπους δεδομένων όπως byte, short, int, long, double, float κλπ. 
 + 
 +Παρακάτω παρατίθεται το παραπάνω πρόγραμμα αλλαγμένο ώστε να χρησιμοποιεί τα [[https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html|DataInputStream]] και [[https://docs.oracle.com/javase/8/docs/api/java/io/DataOutputStream.html|DataOutputStream]]. 
 + 
 +<code java DataInputOutputStreamTest.java> 
 +import java.nio.*; 
 +import java.io.*; 
 + 
 +public class DataInputOutputStreamTest { 
 +   
 +  /* this method is only for debugging. 
 +   * Comment out code, where method is called. 
 +   */ 
 +  public static void print_array(byte[] array) { 
 +    int i=0; 
 +    for(byte b: array) { 
 +      System.out.format("%x", b); 
 +      if(++i % 2 == 0) 
 +        System.out.print(" "); 
 +    } 
 +    System.out.println(); 
 +  } 
 +   
 +  public static void main(String []args ) { 
 +    File file = new File("file.bin"); 
 +    write(file); 
 +    read(file); 
 +  } 
 +   
 +  public static void write(File file) { 
 +    int a = -159954; 
 +    double b = 125.128953; 
 +    char c = 'Θ'; 
 +    String str = "Πώς είσαι;"; 
 +     
 +    try(DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) { 
 +      out.writeInt(a); 
 +      out.writeDouble(b); 
 +      out.writeChar(c); 
 +      byte [] bytes_str = str.getBytes(java.nio.charset.StandardCharsets.UTF_16); 
 +      out.write(bytes_str, 0, bytes_str.length); 
 +    } 
 +    catch(IOException ex) { 
 +      System.out.println("Cannot write to file: "+file.getName());   
 +    } 
 +  } 
 +   
 +  public static void read(File file) { 
 +     
 +    try(DataInputStream in = new DataInputStream(new FileInputStream(file))) { 
 +      int a = in.readInt(); 
 +      double b = in.readDouble(); 
 +      char c = in.readChar(); 
 +      byte [] bytes = new byte[512]; 
 +      int str_size = in.read(bytes); 
 +       
 +      System.out.println(a); 
 +      System.out.println(b); 
 +      System.out.println("'"+c+"'"); 
 +      System.out.println(new String(bytes, 0, str_size, java.nio.charset.StandardCharsets.UTF_16)); 
 +    } 
 +    catch(IOException ex) { 
 +       System.out.println("Something bad happened!");  
 +    }
          
   }   }
Line 92: Line 180:
  
 <WRAP tip 80% center round> <WRAP tip 80% center round>
-H //default// υλοποίηση ενός [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html|ByteBuffer]] καταχωρεί τα δεδομένα ή διαβάζει τα δεδομένα κατά big-endian. Εάν θέλετε να αλλάξετε τη μορφή καταχώρησης των δεδομένων στο buffer μπορείτε να χρησιμοποιήσετε τη μέθοδο [[https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#order-java.nio.ByteOrder-|order]]. H μέθοδος λαμβάνει ένα αντικείμενο της κλάσης ByteOrder, το οποίο είναι ένα εκ των **BIG_ENDIAN** ή **LITTLE_ENDIAN**.+Η κλάσεις [[https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html|DataInputStream]] και [[https://docs.oracle.com/javase/8/docs/api/java/io/DataOutputStream.html|DataOutputStream]] δεν δίνουν τη δυνατότητα να αλλάξετε το endianness των τύπων που αποθηκεύονται στο stream. 
 </WRAP> </WRAP>
 +
 +<WRAP todo 80% center round>
 +Παρατηρήστε ότι και στις δύο περιπτώσεις μπορείτε να αλλάξετε την κωδικοποίηση των Strings που αποθηκεύονται μέσα στο stream. Στα παραπάνω παραδείγματα αλλάξτε την κωδικοποίηση σε UTF-8 από UTF-16.
 +</WRAP>
 +
 +|Προηγούμενο: [[:java:byte_streams | Ροές δυαδικών δεδομένων ]] | [[:toc | Περιεχόμενα ]] | Επόμενο: [[:java:character_streams | Ροές χαρακτήρων]] |
  
java/byte_streams_to_data.1583332702.txt.gz · Last modified: 2020/03/04 14:38 by gthanos