February 15, 2017

I/O Streams

အရင်တစ်ခေါက် File အကြောင်းရေးသားခဲ့စဉ်က File တွေ Directory တွေကို Create လုပ်နိုင်တယ်။ ပြီးတော့လဲ Delete လုပ်နိုင်တယ်။ အမည်ပြောင်းတာတို့လဲ လုပ်နိုင်ခဲ့ပါတယ်။ ဒါပေမဲ့ အဲ့ဒီ File တွေထဲက Data တွေကို Read လုပ်တာတို့ Write လုပ်တာတို့ကို မလုပ်နိုင်ခဲ့ပါဘူး။

File ထဲက Data တွေကို Input Output လုပ်နိုင်ဖို့အတွက် I/O Stream တွေကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Java Language မှာ I/O Stream တွေကို အသုံးပြုမည့် Data Type အပေါ်မူတည်ပြီး အမျိုးမျိုးပြင်ဆင်ထားပါတယ်။ ပြီးတော့ I/O Stream တွေကို ရေးသားတဲ့နေရာမှာလဲ Design Pattern တွေကို အသုံးပြုရေးသားထားပါတယ်။ အရင်ဆုံး I/O Stream တွေကို လေ့လာတဲ့နေရာမှာ အသုံးပြုနိုင်တဲ့ I/O Stream တွေနဲ့ အသုံးပြုပုံတွေကို လေ့လာပြီး၊ နောက်ပိုင်းမှ I/O Stream တွေမှာ အသုံးပြုထားတဲ့ Design Patterns တွေကို လေ့လာသွားပါမယ်။


What are Streams?

Stream တွေဟာ Java Program ထဲမှာအသုံးပြုမည့် Input Source တွေနဲ့ Output Destination တွေကိုကိုယ်စားပြုတဲ့ Interface Object တွေဖြစ်ကြပါတယ်။ Source တွေကော Destination တွေပါ ပုံစံအမျိုးမျိုးရှိနိုင်ကြပြီး Input Output လုပ်ကြမည့် Data တွေလဲ​အမျိုးမျိုးဖြစ်နိုင်ပါတယ်။

Input Source လိုပြောတဲ့နေရာမှာ File တစ်ခုလဲဖြစ်နိုင်သလို System Console ကလာတဲ့ Input လဲ ဖြစ်နေနိုင်ပါတယ်။ ဒါမှမဟုတ် အခြားသော Program တစ်ခုခုလဲ ဖြစ်နိုင်ပါတယ်။ ဒီလိုပဲ Output Destination လို့ပြောတဲ့နေရာမှာလဲ File တစ်ခုခု၊ System Console ဒါမှမဟုတ် အခြားသော Program တစ်ခုခုလဲ ဖြစ်နေနိုင်ပါတယ်။ ဒါပေမဲ့ အခြေခံအားဖြင့်တော့ I/O Stream တွေကို Input Stream တွေနဲ့ Output Streams တွေဆိုပြီး သတ်မှတ်ထားပါတယ်။


Input Streams


Java Program ထဲကအသုံးပြုရန် Data များအား Source တစ်နေရာရာမှ ဖတ်ယူနိုင်ဖို့အတွက် Input Stream များကို အသုံးပြုရပါတယ်။ အသုံးပြုလိုတဲ့ Data Type အပေါ်မူတည်ပြီး Streams အမျိုးမျိုးကိုလဲ ပြင်ဆင်ထားပါတယ်။ အသုံးပြုနိုင်တဲ့ Data Type တွေကတော့ bytes, primitive type data, localize character များနဲ့ Object တွေပဲ ဖြစ်ကြပါတယ်။


Output Streams


Java Program ထဲကနေ Destination တစ်ခုဆီကို Data များကို Output လုပ်ချင်တဲ့အခါ Output Stream တွေကို အသုံးပြုနိုင်ပါတယ်။ Destination အနေနဲ့ File တစ်ခုခုဖြစ်နိုင်သလို၊ System Console လဲ ဖြစ်နိုင်သလို အခြားသော Program တစ်ခုခုလဲ ဖြစ်နိုင်ပါတယ်။ ပြီးတော့ byte အနေနဲ့သော်၎င်း၊ primitive data type အနေနဲ့သော်၎င်း၊ localize character များအနေနဲ့သော်၎င်း၊ Object များအနေနဲ့သော်၎င်း Outputလုပ်နိုင်ပါတယ်။

Input Stream တုန်းကလိုပဲ အသုံးပြုလိုတဲ့ Data Type တွေအလိုက် Stream တွေကို ရွေးချယ် အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Data Types and Streams


Java IO ရဲ့ Stream Class တွေအားလုံးဟာ InputStream နဲ့ OutputStream Class တွေကနေ ဆင်းသက်လာကြတဲ့ Class တွေဖြစ်ပါတယ်။ Input Output အနေနဲ့ အသုံးပြုလိုတဲ့ Data Type အလိုက် Stream တွေကို ခွဲခြားအသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

Data Types Input Streams Output Streams
Byte FileInputStream FileOutputStream
Characters FileReader FileWriter
String Line BufferedReader PrintWriter
Primitive Data DataInputStream DataOutputStream
Objects ObjectInputStream ObjectOutputStream


Byte Streams


File တစ်ခုထဲက Data တွေကို Binary Data တွေဖြစ်တဲ့ 8-bit bytes ပုံစံနဲ့ Read Write လုပ်လိုတဲ့အခါ Byte Streams တွေကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Byte Stream တွေအားလုံးဟာ InputStream နဲ့ OutputStream Class တွေရဲ့ Sub Class တွေဖြစ်ကြပြီး အသုံးများတာကတော့ FileInputStream နဲ့ FileOutputStream Class တို့ပဲ ဖြစ်ကြပါတယ်။

FileInputStream ကတော့ File တစ်ခုကနေ Byte တွေကို Read လုပ်ချင်တဲ့အခါမှာ အသုံးပြုနိုင်တဲ့ Stream တစ်ခုဖြစ်ပြီး၊ FileInputStream Object ကို တည်ဆောက်ရန် Constructor ၃ မျိုးပြင်ဆင်ထားပါတယ်။

Constructor Description
FileInputStream(File file) Input လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileInputStream(FileDescription fdObj) Input လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileInputStream(String name) Input လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်

FileInputStream Object ကနေ byte တွေကို 1 byte ချင်း Read လုပ်လိုတဲ့အခါ read() ဆိုတဲ့ Method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

FileOutputStream ကတော့ File တစ်ခုဆီကို Byte တွေ အနေနဲ့ Output လုပ်ပေးနိုင်တဲ့ Stream Object တစ်ခု ဖြစ်ပါတယ်။ FileOutputStream Object ကို တည်ဆောက်ဖို့အတွက် ပြင်ဆင်ထားတဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileOutputStream(File file) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(File file, boolean append) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileOutputStream(FileDescription fdObj) Output လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(String name) Output လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileOutputStream(String name, boolean append) Output လုပ်မည့် File ရဲ့ အမည်ကို String Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်

Output လုပ်လိုတဲ့ Byte Data တွေကို ရေးသားနိုင်ဖို့အတွက် write(int b), write(byte [] b) နဲ့ write(byte [] b, int off, int len) method တို့ကို ပြင်ဆင်ထားပါတယ်။ 1 byte ချင်း Write လုပ်ချင်ရင်တော့ write(int b) ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

Stream Object တွေဟာ Resource တွေကို အသုံးပြုနေတဲ့ Object အမျိုးအစား ဖြစ်တဲ့အတွက် အသုံးပြုပြီးတဲ့အခါမှာ ပြန်ပြီး ပိတ်ပေးဖို့လိုအပ်တဲ့အတွက် close() ဆိုတဲ့ Method ကိုလဲ ပြင်ဆင်ပေးထားပါတယ်။ ဒါပေမဲ့ Java SE 7 ရဲ့ ရေးသားပုံအသစ်ဖြစ်တဲ့ try-with-resource ရေးသားပုံနဲ့ ရေးသားမယ်ဆိုရင်တော့ အလိုအလျောက် ပိတ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။
package com.jdc.io.stream.ep1;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyByte {

    public static void main(String[] args) {
        
        try (FileInputStream in = new FileInputStream("from.txt");
                FileOutputStream out = new FileOutputStream("to.txt")){
            
            int i = 0;
            
            while((i = in.read()) != -1) {
                out.write(i);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

အထက်ပါနမူနာကတော့ from.txt ဆိုတဲ့ File ထဲမှာရှိတဲ့ Data တွေကို 1 byte ချင်း read လုပ်ပြီး to.txt ဆိုတဲ့ဖိုင်ထဲကို 1 byte ချင်း write လုပ်နေတဲ့ နမူနာဖြစ်ပါတယ်။

FileInputStream နဲ့ FileOutputStream Object တွေကို try with resource နဲ့ ရေးသားထားတဲ့အတွက် နောက်ဆုံးမှာ အလိုအလျောက်ပိတ်ပေးသွားမှာ ဖြစ်တယ်။ အဲ့ဒီအတွက် တကူးတက close လုပ်ပေးစရာမလိုတော့ ပါဘူး။ တဖန် while clause ထဲမှာ i = in.read() ဆိုပြီး FileInputStream ကနေ 1 byte ချင်း Read လုပ်နေပါတယ်။ နောက်ဆုံး Read လုပ်စရာမရှိတော့တဲ့အခါ -1 ကို Return ပြန်မှာ ဖြစ်ပြီး While loop ထဲကနေ ထွက်သွားမှာ ဖြစ်ပါတယ်။

While Loop ထဲမှာတော့ Read လုပ်လာတဲ့ တန်ဖိုးကို 1 byte ချင်း FileOutputStream ကို သုံးပြီး write လုပ်ပေးနေပါတယ်။ ဤနည်းအားဖြင့် from.txt ဖိုင်ထဲက Data တွေကို to.txt ဖိုင်ထဲကို 1 byte ချင်း Write လုပ်ပေးသွားနိုင်မှာ ဖြစ်ပါတယ်။


Character Streams

Text File တစ်ခုအတွင်းရှိ Data များကို Character ပုံစံနဲ့ Read / Write လုပ်ချင်ရင် Character Streams များကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။ Character Streams တွေဟာ InputStreamReader နဲ့ OutputStreamWriter တို့ရဲ့ Sub Class တွေ ဖြစ်ကြပြီး FileReader နဲ့ FileWriter တို့ဟာ အသုံးများပါတယ်။

FileReader နဲ့ FileWriter တို့ဟာ Default Encoding နဲ့ Character တွေကို အလွယ်တကူ Read / Write လုပ်နိုင်အောင်ပြင်ဆင်ထားတဲ့ Class တွေဖြစ်ကြပြီး၊ Character Set တို့ကို ကိုယ်တိုင် သတ်မှတ်ပြီး Read / Write လုပ်ချင်ရင်တော့ InputStreamReader နဲ့ OutputStreamWriter တို့ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။

FileReader ကို Character များကို Read လုပ်တဲ့နေရာမှာ အသုံးပြုပြီး ရေးသားနိုင်တဲ့ Constructor များကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileReader(File file) Input လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileReader(FileDescription fdObj) Input လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileReader(String name) Input လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်

FileWriter ကို Character များကို Write လုပ်တဲ့နေရာမှာ အသုံးပြုပြီး ရေးသားနိုင်တဲ့ Constructor များကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
FileWriter(File file) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(File file, boolean append) Output လုပ်ရမည့် File ကို ကိုယ်စားပြုတဲ့ File Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileWriter(FileDescription fdObj) Output လုပ်မည့် File ကို ဖေါ်ပြပေးနိုင်တဲ့ FileDescriptor Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(String name) Output လုပ်မည့် File ရဲ့ အမည် String Object ကို Argument အနေနဲ့ အသုံးပြုရပါမယ်
FileWriter(String name, boolean append) Output လုပ်မည့် File ရဲ့ အမည်ကို String Object နဲ့ boolean တန်ဖိုးတစ်ခုကို Argument အနေနဲ့ ပေးရပါမယ်။
boolean ရဲ့ တန်ဖိုးဟာ true ဖြစ်မယ်ဆိုရင် လက်ရှိရှိပြီးသား File မှာ Output လုပ်လာတဲ့ Data တွေကို ဆက်ပြီးထည့်ပေးနိုင်မှာ ဖြစ်ပါတယ်
FileReader နဲ့ FileWriter တို့ရဲ့ အသုံးပြုပုံဟာ အခြေခံအားဖြင့် FileInputStream နဲ့ FileOutputStream တို့နဲ့အတူတူပဲ ဖြစ်ပါတယ်။
package com.jdc.io.stream.ep2;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyChar {
    
    public static void main(String[] args) {
        
        try(FileReader in = new FileReader("from.txt");
                FileWriter out = new FileWriter("out.txt")) {
            
            int c = 0;
            
            while((c = in.read()) != -1) {
                out.write(c);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

FileReader ကို အသုံးပြုပြီး Text File အတွင်းမှ Character များကို Read လုပ်ရာမှာ read() method ကို အသုံးပြုနိုင်မှာဖြစ်ပါတယ်။ Return Type မှာ int ဖြစ်ပြီး Character တစ်လုံးကို ကိုယ်စားပြုမှာ ဖြစ်ပါတယ်။ နောက်ဆုံး Read လုပ်စရာမရှိတော့တဲ့အခါ -1 ကို Return ပြန်မှာဖြစ်ပါတယ်။

Character စာလုံးများကို Write လုပ်လိုတဲ့အခါ FileWriter Object ရဲ့ write(int char) method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ Write Method ကို အသုံးပြုပြီး Character တစ်လုံးချင်းစီကို Output လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။

အထက်ပါနမူနာထဲံမှာတော့ from.txt file ထဲမှ Character များကို while statement ဖြင့် တစ်လုံးစီဖတ်ပြီး out.txt file ထဲကို Character တစ်လုံးစီ Output လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။


Line Oriented IO


Character I/O ကို အသုံးပြုတဲ့အခါမှာ Character တစ်လုံးခြင်း Read / Write လုပ်တာထက် ဒီထက်ပိုပြီး ကြီးမားတဲ့ Unit နဲ့ Read / Write လုပ်လေ့ရှိပါတယ်။ အသုံးများတာက စာကြောင်း တစ်ကြောင်းစီကို Read / Write လုပ်တဲ့ပုံစံပဲ ဖြစ်ပါတယ်။ Line တစ်ခုချင်းစီကို Read / Write လုပ်ဖို့အတွက် BufferedReader, BufferedWriter နဲ့ PrintWriter တို့ကို အသုံးပြုနိုင်ပါတယ်။


BufferedReader

BufferedReader တွေဟာ Text File တွေကနေ Character တွေကို သတ်မှတ်ထားတဲ့ Buffered Size အလိုက် Character Array အဖြစ်သော်၎င်း၊ စာကြောင်းတစ်ကြောင်းစီလိုက်သော်၎င်း Read လုပ်နိုင်အောင်ပြင်ဆင်ထားတဲ့ Class တွေ ဖြစ်ပါတယ်။

BufferedReader Class ကို Object ဆောက်နိုင်တဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ပါတယ်။

Constructor Description
BufferedReader(Reader in) Reader Object တစ်ခုကို Argument အနေနဲ့ပေးရပါမယ်။​ Buffer Size ကိုတော့ Default Size အတိုင်း အသုံးပြုသွားမှာ ဖြစ်ပါတယ်။
BufferedReader(Reader in, int size) Reader Object တစ်ခုနဲ့ Buffer Size ကို Argument အနေနဲ့ ပေးပြီး BufferedReader Object တစ်ခုကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Buffer Size ကို သတ်မှတ်ပြီး အသုံးပြုလိုပါက ဤ Constructor ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep3;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class LineReader {
    
    public static void main(String[] args) {
        
        try(BufferedReader in = new BufferedReader(new FileReader("line.txt"))) {
            
            String line = null;
            
            while((line = in.readLine()) != null) {
                System.out.println(line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

BufferedReader ကနေ စာကြောင်း တစ်ကြောင်းစီ Read လုပ်လိုပါက readLine() method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ အထက်ပါ နမူနာမှာတော့ in.readLine() ကို အသုံးပြုပြီး line variable မှာ အစားထိုးနေပါတယ်။ ပြီးတော့ While Statement မှာ line ဟာ null မဖြစ်မခြင်း loop ပတ်နေမှာ ဖြစ်ပြီး စာကြောင်းတွေ ဖတ်စရာကုန်သွားရင် null ကို Return လုပ်မှာ ဖြစ်တဲ့အတွက် looping ထဲကနေ ထွက်သွားပါလိမ့်မယ်။

ဒါ့ကြောင့် line.txt ထဲက စာကြောင်းတွေကို အစ စာကြောင်းကနေ တစ်ကြောင်းချင်း ကုန်သွားသည် အထိ Read လုပ်သွားနိုင်မှာ ဖြစ်ပါတယ်။


PrintWriter


Java Program ထဲကနေ Character တွေကို String အနေနဲ့ Write လုပ်လိုတဲ့အခါမှာ PrintWriter ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ PrintWriter ကို အသုံးပြုပြီး String တွေလို ဒီအတိုင်း Write လုပ်နိုင်သလို၊ Format ချပြီးလဲ Write လုပ်နိုင်ပါတယ်။ ထို့အပြင် Locale အလိုက်သတ်မှတ်ပြီးလဲ Format လုပ်နိုင်မှာ ဖြစ်ပါတယ်။ PrintWriter Object ကို တည်ဆောက်နိုင်တဲ့ Constructor တွေကတော့ အောက်ပါ အတိုင်းဖြစ်ကြပါတယ်။

Constructor Description
PrintWriter(File file) Output File ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(File file, String csn) Output File နဲ့ Character Set ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(OutputStream out) OutputStream ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(OutputStream out, boolean autoFlush) OutputStream နဲ့ Auto Flush Mode ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။
PrintWriter(String fileName) File Name ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(String fileName, String csn) File Name နဲ့ Character Set ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(Writer out) Writer ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။ Auto Flush ကိုတော့ လုပ်ပေးနိုင်မှာ မဟုတ်ပါဘူး
PrintWriter(Writer out, boolean autoFlush) Writer နဲ့ Auto Flush Mode ကို သတ်မှတ်ပြီး PrintWriter Object ကို တည်ဆောက်နိုင်မှာ ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep3;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class LineWriter {

    private static final String [] ARRAY = {
            "Hello Java",
            "Hello Java IO",
            "Learn java Programming."
    };
    
    public static void main(String[] args) {
        
        try(PrintWriter out = new PrintWriter(new FileWriter("line.txt"))) {
            
            for (String line : ARRAY) {
                out.println(line);
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

String တွေကို Write လုပ်ဖို့အတွက် print(String str) ဒါမှမဟုတ် write(String str) ကို အသုံးပြုနိုင်ပါတယ်။ ဒါအပြင် Line တွေကို Write လုပ်ဖို့အတွက် println(String str) ကို အသုံးပြုနိုင်ပါတယ်။ Format လုပ်ချင်ရင်တော့ printf(String format, String … param) ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Data Streams

Primitive Data နဲ့ String တန်ဖိုး တွေကို Read / Write လုပ်ချင်တဲ့အခါ DataInputStream နဲ့  DataOutputStream တို့ကို အသုံးပြုနိုင်ပါတယ်။

Constructor Description
DataOutputStream(OutputStream out) OutputStream Object တစ်ခုကို အသုံးပြုပြီး DataOutputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။
DataInputStream(InputStream in) InputStream Object တစ်ခုကို အသုံးပြုပြီး DataInputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

အသုံးပြုလိုတဲ့ Data Type အလိုက် Method တွေကိုလဲ ခွဲခြားပြင်ဆင်ထားပါတယ်။

Data Type DataInputStream DataOutputStream
boolean readBoolean() writeBoolean(boolean v)
char readChar() writeChar(int v)
byte readByte() writeByte(int v)
short readShort() writeShort(int v)
int readInt() writeInt(int v)
long readLong() writeLong(long v)
float readFloat() writeFloat(float v)
double readDouble() writeDouble(doble v)
String readUTF() writeUTF(String str)

မိမိအသုံးပြုလိုတဲ့  Data Type အလိုက် သက်ဆိုင်ရာ Method ကို အသုံးပြုပြီး ရေးသားရမှာ ဖြစ်ပါတယ်။


Write Data

package com.jdc.io.stream.ep4;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class DataOutput {
    
    private static final String name = "Aung Aung";
    private static final int age = 20;
    private static final boolean isMan = true;
    
    public static void main(String[] args) {
        
        System.out.println("Starting Output");

        try(DataOutputStream out = new DataOutputStream(new FileOutputStream("data.dat"))) {
            
            out.writeUTF(name);
            out.writeInt(age);
            out.writeBoolean(isMan);
            
            System.out.println("End Output");
        } catch (IOException e) {
            System.out.println("Output Error");
        }
        
    }

}

အထက်ပါနမူနာမှာတော့ name variable ဟာ String ဖြစ်တဲ့အတွက် writeUTF ကို အသုံးပြုပြီး၊ age ဟာ int ဖြစ်တဲ့အတွက် writeInt ကို အသုံးပြုပါတယ်။ တဖန် isMan ဆိုတဲ့ Variable ဟာ boolean type ဖြစ်တဲ့အတွက် writeBoolean ကို အသုံးပြရမှာ ဖြစ်ပါတယ်။


Reading Data

package com.jdc.io.stream.ep4;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class DataInput {

    public static void main(String[] args) {
        
        try(DataInputStream in = new DataInputStream(
                new FileInputStream("data.dat"))) {
            
            System.out.println("Name : " + in.readUTF());
            System.out.println("Age  : " + in.readInt());
            System.out.println("Male : " + in.readBoolean());
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

အထက်ပါ နမူနာကတော့ DataOutput ဖြင့် Write လုပ်ထားတဲ့ data.dat file ထဲက Data တွေကို ပြန်ပြီး Read လုပ်နေတာဖြစ်ပါတယ်။ String Data တွေကို readUTF ကိုအသုံးပြုပြီး၊ int ကိုတော့ readInt ကို အသုံးပြုပါတယ်။ တဖန် boolean ကိုတော့ readBoolean method ကို အသုံးပြုပါတယ်။


Serialization

အရှေ့တွင်ဖေါ်ပြခဲ့သလို Java ဘာသာရပ်တွင် Byte, Character, Primitive Data များနှင့် String များကို Read / Write လုပ်နိုင်တဲ့အပြင် Object တွေကိုလဲ Object အတိုင်း Read / Write လုပ်နိုင်ပါတယ်။

Java ဘာသာရပ်မှာ JVM Memory အပေါ်မှာရှိတဲ့ Object တွေကို အခြား တစ်နေနေရာကို ပို့ပေးလိုက်ခြင်းကို Serialize လုပ်တယ်လို့ခေါ်ပါတယ်။ တဖန် တစ်ခြားတစ်နေနေရာကနေလာတဲ့ Serialized လုပ်ထားတဲ့ Data တွေကနေ JVM Memory အပေါ်ကို ပြန်ပြီး Object အဖြစ်ပြန်ပြောင်းတာကိုတော့ Deserialize လုပ်တယ်လို့ခေါ်ပါတယ်။ Deseiralize လုပ်တယ်ဆိုတာကလဲ Serialize လုပ်ထားတဲ့ Data များကိုသာ ပြုလုပ်နိုင်မှာ ဖြစ်ပါတယ်။

နမူနာအားဖြင့် Program ထဲမှာ သုံးနေတဲ့ Java Object တွေကို File တစ်ခုခုမှာ သွားသိမ်းတာတို့၊ Internet ကိုဖြတ်ပြီး တစ်ခြားတစ်နေနေရာကိုပို့ပေးတာတို့ဟာ Serialize လုပ်တာဖြစ်ကြပါတယ်။ Server အပေါ်မှာရှိတဲ့ Object တွေကို Session ပေါ်မှာ သုံးနေတယ်ဆိုတာကလဲ Serialize လုပ်နေတာပဲ ဖြစ်ပါတယ်။

ဒါဖြင့် ဘယ်လို Object တွေကို Serialize လုပ်လို့ရတာလဲ။ Primitive Data Type တွေ၊ Serializable Interface ကို Implement လုပ်ထားတဲ့ Object တွေနဲ့ Serializable Object တွေရဲ့ Collection တွေ ဆိုရင် Serialize လုပ်လို့ရမှာ ဖြစ်ပါတယ်။

Object တစ်ခုကို Serialize လုပ်တဲ့အခါမှာ Object ရဲ့ State တွေဖြစ်ကြတဲ့ Instance Variable တွေကိုသာ Serialize လုပ်သွားမှာ ဖြစ်ပါတယ်။ ဒါ့ကြောင့် Serialize လုပ်မည့် Object ရဲ့ Instance Variable တွေဟာလဲ Serializable ဖြစ်ဖို့လိုအပ်ပါတယ်။ တကယ်လို့ Serialize မလုပ်ချင်တဲ့ Instance Variable တွေဆိုရင် transient modifier ကို ရေးသားပြီး ဖေါ်ပြနိုင်ပါတယ်။ Instance Variable တွေရှေ့မှာ transient ကို ရေးသားထားရင် အဲ့ဒီ Field ကို Serialize လုပ်မှာ မဟုတ်တော့ပါဘူး။
package com.jdc.io.stream.ep5;

import java.io.Serializable;

public class Employee implements Serializable{

    private static final long serialVersionUID = 1L;

    private int id;
    private String name;
    private String phone;
  
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
}


Serial Version UID

Serializable Object တစ်ခုကို Serialize လုပ်ပြီး ပြန်ပြီး Deserialize လုပ်တဲ့အခါ Serial Version UID ကို အသုံးပြုပြီး Class ရဲ့ Version မှန်မမှန်ကို ပြန်ပြီး စစ်ဆေးလေ့ရှိပါတယ်။ Serial Version UID ကို ရေးသားရာမှာ static final long serialVersionUID ဆိုတဲ့ပုံစံနဲ့ ရေးသားပေးရပါတယ်။ Access Modifier ကိုတော့ နှစ်သက်ရာ ရေးသားအသုံးပြုနိုင်ပါတယ်။

Serialize လုပ်တဲ့အခါမှာ Serial Version UID ဟာ Static Variable ဖြစ်ပေမဲ့ ခြွင်းချက်အနေနဲ့ Serialize အလုပ်ခံရမှာ ဖြစ်ပါတယ်။ Deserialize လုပ်တဲ့အခါမှာ လက်ရှိ Class နဲ့ Deserialize လုပ်မည့် Object ရဲ့ Serial Version UID ကို တိုက်စစ်ပြီး မှန်ကန်မှသာ Serialize လုပ်ပေးမှာ ဖြစ်ပါတယ်။ တကယ်လို့ Version နှစ်ခုမတူညီခဲ့ပါက InvalidClassException ကို ဖြစ်ပေါ်စေမှာ ဖြစ်ပါတယ်။

တကယ်လို့ Serializable Class တစ်ခုမှာ Serial Version UID ကို မရေးထားဖူးဆိုရင် Serialize လုပ်တဲ့အခါမှာ JVM ကနေ နှစ်သက်ရာ ID တစ်ခုကို Generate လုပ်ပေးမှာ ဖြစ်ပါတယ်။

ဒါပေမဲ့ Serial Version UID Calculation ဟာ Compiler Implementation အပေါ်မူတည်ပြီး ပြောင်းလဲတတ်တဲ့အတွက် Serial Version UID ကို Class အတွင်းမှာ မဖြစ်မနေရေးသားသင့်ပါတယ်။


Writing Objects (Serialization)

Java Program ထဲကနေ Memory အပေါ်မှာရှိတဲ့ Serializable Object တွေနဲ့ Serializable Object ရဲ့ Collection တွေကို Serialize လုပ်လိုတဲ့အခါမှာ ObjectOutputStream ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ ObjectOutputStream ကို အသုံးပြုပြီး Primitive Data တွေနဲ့ Serializable Object Graphs တွေကို Serialize လုပ်ပေးနိုင်မှာ ဖြစ်ပါတယ်။

Object တွေကို Serialize လုပ်တဲ့နေရာမှာလဲ File တွေမှာလဲ Serialize လုပ်နိုင်သလို Network ကို အသုံးပြုတဲ့ Socket Stream တွေနဲ့လဲ တွဲဖက် အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။ ObjectOutputStream ရဲ့ Constructor တွေကတော့ အောက်ပါအတိုင်း ဖြစ်ကြပါတယ်။

Constructor Description
ObjectOutputStream() ObjectOutputStream ရဲ့ Sub Class တွေအတွက် ပြင်ဆင်ထားပေးတဲ့ Constructor ဖြစ်ပါတယ်။
ObjectOutputStream(OutputStream out) OutputStream Object တစ်ခုကို အသုံးပြုပြီး ObjectOuputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep5;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class ObjectWriteTest {

    public static void main(String[] args) {
        Employee e = new Employee();
        e.setId(1);
        e.setName("Aung Aung");
        e.setPhone("09788986677");
        
        try(ObjectOutputStream out = new ObjectOutputStream(
                new FileOutputStream("employee.obj"))) {
            out.writeObject(e);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
}
အထက်ပါနမူနာအတိုင်း JVM Memory အပေါ်မှာရှိတဲ့ Object တွေကို Serialize လုပ်လိုပါက writeObject(Object obj) method ကို အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။


Reading Objects (Deserialization)

ObjectOutputStream ကို အသုံးပြုပြီး Serialize လုပ်ထားတဲ့ Primitive Data တွေနဲ့ Object တွေကို Deserialize လုပ်လိုတဲ့အခါ ObjectInputStream ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

File ထဲမှာရှိတဲ့ Data တွေကို Deserialize လုပ်တဲ့အခါမျိုးမှာ ObjectInputStream ဟာ FileInputStream ကို အသုံးပြုပါတယ်။ ဒါကြောင့် File ထဲက Data တွေကို Read လုပ်လိုတဲ့အခါမျိုးမှာ InputStream Parameter နေရာမှာ FileInputStream Object ကို အသုံးပြုရမှာ ဖြစ်ပါတယ်။

တဖန် Remote System တစ်ခုကနေ Data တွေကို ရယူတဲ့အခါမျိုးမှာတော့ Socket Streams ကို အသုံးပြုပြီး Data တွေကို Deserialize လုပ်နိုင်ပါတယ်။

Constructor Description
ObjectInputStream() ObjectInputStream ရဲ့ Sub Class တွေအတွက် ပြင်ဆင်ထားပေးတဲ့ Constructor ဖြစ်ပါတယ်။
ObjectInputStream(InputStream in) OutputStream Object တစ်ခုကို အသုံးပြုပြီး ObjectOuputStream ကို တည်ဆောက်ရန် ပြင်ဆင်ထားတဲ့ Constructor ဖြစ်ပါတယ်။

package com.jdc.io.stream.ep5;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ObjectReadTest {

    public static void main(String[] args) {
        
        try(ObjectInputStream in = new ObjectInputStream(
                new FileInputStream("employee.obj"))) {
            
            Employee e = (Employee) in.readObject();
            
            System.out.println(e.getName());
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

ယခင် နမူနာဖြင့် Serialize လုပ်ထားတဲ့ Employee Object ကို Deserialize လုပ်လိုတဲ့အခါ အထက်ပါအတိုင်း ObjectInputStream ကို အသုံးပြုပြီး ရေးသားနိုင်ပါတယ်။ အထက်ပါအတိုင်း in.readObject() method ရဲ့ Return Type ဟာ Object ဖြစ်နေတဲ့အတွက် Employee အဖြစ်ပြန်ပြီး Cast လုပ်ပေးဖို့လိုအပ်ပါတယ်။

ဆက်ပါဦးမယ်
မင်းလွင်

No comments:

Post a Comment