کلاس های ObjectInputStream و ObjectOutputStream

در این آموزش با کلاس های ObjectInputStream و ObjectOutputStream برای خواندن و نوشتن شی از فایل آشنا می شویم ، از آنجایی که این دو کلاس مکمل یکدیگر هستند با هر دوی آن ها در یک آموزش آشنا می شویم.اگر از ObjectOutputStream برای نوشتن شی در فایل استفاده کنیم حتماً باید از ObjectInputStream برای خواندن شی از آن فایل استفاده کنیم و اگر قصد استفاده از ObjectInputStream را داشته باشیم باید مطمئن شویم که فایل مورد نظر قبلاً با ObjectOutputStream ایجاد شده است ، لذا آموزش این دو کلاس در دو مبحث جدا ممکن نیست و در این آموزش با هر دو کلاس آشنا می شویم. مهم ترین کاربرد این دو کلاس ذخیره شی و خواندن شی از فایل است با این حال این دو کلاس متد های کمکی دیگری نیز دارند که کار با داده های مختلف را ساده تر می کنند.

کلاس ObjectOutputStream

از این کلاس برای ذخیره سازی شی در فایل استفاده می شود. برای استفاده از این کلاس باید از سازنده زیر برای ساخت شی جدید از آن استفاده کنیم :

ObjectOutputStream (OutputStream out)

متد های پر کاربرد ObjectOutputStream در جدول زیر آمده است:

متد کاربرد
close () جریان خروجی را بسته و منابع استفاده شده را آزاد می کند
flush() داده های بافر شده را به سمت خروجی ارسال می کند.
write(byte[] b) یک آرایه از بایت ها را در جریان خروجی می نویسد.
write(byte[] b,int offset,int length) یک قسمت از یک آرایه از بایت ها را در جریان خروجی می نویسد.
write(int v) یک بایت در جریان خروجی می نویسد.
writeBoolean(boolean b) یک مقدار boolean در جریان خروجی می نویسد.
writeByte(int v) یک بایت هشت بیتی را در جریان خروجی می نویسد.
writeBytes(String str) یک رشته را به آرایه ای از بایت ها تبدیل کرده و در جریان خروجی می نویسد.
writeChar(int v) یک کاراکتر شانزده بیتی را در جریان خروجی می نویسد.
writeDouble(double d) یک مقدار double را در جریان خروجی می نویسد.
writeFloat(float f) یک مقدار float را در جریان خروجی می نویسد.
writeInt(int i) یک مقدار int را در جریان خروجی می نویسد.
writeLong(long l) یک مقدار long را در جریان خروجی می نویسد.
writeObject(Object obj) مهم ترین متد این کلاس است و یک شی جاوایی را در جریان خروجی می نویسد.
writeShort(int v) یک مقدار short را در جریان خروجی می نویسد.

کلاس ObjectInputStream

از این کلاس برای خواندن یک شی از یک جریان ورودی استفاده می شود. برای استفاده از این کلاس باید از سازنده زیر برای ساخت شی جدید از آن استفاده کنیم :

ObjectInputStream (InputStream in)

متد های پر کاربرد ObjectInputStream در جدول زیر آمده است:

متد کاربرد
close () جریان ورودی را بسته و منابع استفاده شده را آزاد می کند
read() یک بایت از جریان ورودی میخواند.
read(byte[] b) یک آرایه از بایت ها را از جریان ورودی میخواند.
read(byte[] b,offset,length) به تعداد length بایت از جریان ورودی میخواند و با شروع از اندیس offset در آرایه b می نویسد.
readBoolean() یک مقدار boolean را از جریان ورودی می خواند.
readByte() یک بایت هشت بیتی را از جریان ورودی می خواند.
readChar() یک کاراکتر از جریان ورودی می خواند.
readDouble() یک مقدار double را از جریان ورودی می خواند.
readFloat() یک مقدار float را از جریان ورودی می خواند..
readInt() یک مقدار را از جریان ورودی می خواند.
long readLong() یک مقدار long را از جریان ورودی می خواند.
readObjec() مهم ترین متد این کلاس است و یک شی جاوایی را از جریان ورودی می خواند.
readShort() یک مقدار short را از جریان ورودی می خواند.
readUTF() یک رشته متنی را از جریان ورودی می خواند.

نوشتن شی در فایل

در اولین مثال از این بخش یک شی ساده جاوایی از یک کلاس اختصاصی را در فایل می نویسیم. ابتدا یک کلاس ساده به نام Person به صورت زیر ایجاد می کنیم :

import java.io.Serializable;

public class Person implements Serializable
{
    String name;
    String lastName;
    int score;

    public Person(String n, String ln, int i)
    {
        name = n;
        lastName = ln;
        score = i;
    }
    @Override
    public String toString()
    {
        return "[" + name + " : " + lastName + " , " + score + "]";
    }
}

کلاس هایی که قسمت داریم اشیایی از آن را در فایل ذخیره کنیم باید حتماً از نوع Serializable باشند ، در کلاس بالا متد toString را override کردیم تا در آینده چاپ هر شی از آن به سادگی صورت گیرد. با استفاده از کد زیر یک شی از این کلاس ساخته و آن را در فایلی ذخیره می کنیم :

import java.io.*;

public class ObjectOutputStreamDemo
{
    public ObjectOutputStreamDemo()
    {
        Person person = new Person("Jack", "Statham", 15);

        File myFile = new File("G:/Test.obj");
        FileOutputStream fileoutputstream = null;
        ObjectOutputStream objectoutputstream = null;

        try
        {
            fileoutputstream = new FileOutputStream(myFile);
            objectoutputstream = new ObjectOutputStream(fileoutputstream);
            objectoutputstream.writeObject(person);
            objectoutputstream.flush(); 
            objectoutputstream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        new ObjectOutputStreamDemo();
    }
}

در کد بالا ابتدا یک شی نمونه از کلاس مورد نظر ایجاد می کنیم (شی person) ، چون قصد نوشتن این شی در یک فایل را داریم باید یک نمونه از کلاس File ایجاد کرده (شی myFile) و سپس از روی آن یک FileOutputStream ایجاد کنیم (شی fileoutputstream) ، سپس از روی fileoutputstream یک ObjectOutputStream جدید ایجاد می کنیم (شی objectoutputstream) و در نهایت با استفاده از متد writeObject شی مورد نظر را در فایل می نویسیم.در انتها نیز متد های flush و close را فراخوانی می کنیم.

خواندن شی از فایل

الآن آماده ایم تا شی ای که در مرحله قبل در فایل نوشته شده بود را از فایل بخوانیم. برای اینکار کدی به صورت زیر می نویسیم :

import java.io.*;

public class ObjectInputStreamDemo
{
    public ObjectInputStreamDemo()
    {
        File myFile = new File("G:/Test.obj");
        FileInputStream fileinputstream = null;
        ObjectInputStream objectinputstream = null;

        try
        {
            fileinputstream = new FileInputStream(myFile);
            objectinputstream = new ObjectInputStream(fileinputstream);
            Person objInFile = (Person)objectinputstream.readObject();
            System.out.println(objInFile);
            objectinputstream.close();
        }
        catch (IOException | ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        new ObjectInputStreamDemo();
    }
}

از آنجایی که قصد خواندن از فایل را داریم باید ابتدا یک نمونه از کلاس File ایجاد کنیم ، سپس یک FileInputStream از روی آن ایجاد می کنیم (شی fileinputstream) و بعد از آن یک ObjectInputStream جدید از روی fileinputstream ایجاد می کنیم (شی objectinputstream) ، در نهایت با استفاده از متد readObject یک شی از جریان ورودی می خوانیم ولی چون خروجی این متد از نوع کلاس Object است باید آن را به کلاس مورد نظر cast کنیم. در انتها شی خوانده شده را چاپ می کنیم و جریان ورودی را می بندیم. خروجی کد بالا به صورت زیر خواهد بود :

[Jack : Statham , 15]

نوشتن و خواندن چند شی در فایل

با استفاده از متد writeOjbect می توانیم چندین شی در فایل بنویسیم ولی هنگام خواندن از فایل باید به همان ترتیبی که اشیا را در فایل نوشتیم آن ها را از فایل بخوانیم. برای درک بهتر یک کلاس جدید به نام Book به صورت زیر ایجاد می کنیم :

import java.io.Serializable;

public class Book implements Serializable
{
    String title;
    int pages;

    public Book(String t, int p)
    {
        title = t;
        pages = p;
    }

    @Override
    public String toString()
    {
        return "( " + title + " , " + pages + " )";
    }
}

کلاس فوق مشابه کلاس Person است و به توضیح خاصی نیاز ندارد. کد نوشتن در فایل را به صورت زیر تغییر می دهیم :

import java.io.*;

public class ObjectOutputStreamDemo
{
    public ObjectOutputStreamDemo()
    {
        Person firstperson = new Person("John", "Scith", 15);
        Person secondperson = new Person("Jason", "Obimiang", 20);

        Book book = new Book("Core Java", 400);

        File myFile = new File("G:/Test.obj");
        FileOutputStream fileoutputstream = null;
        ObjectOutputStream objectoutputstream = null;

        try
        {
            fileoutputstream = new FileOutputStream(myFile);
            objectoutputstream = new ObjectOutputStream(fileoutputstream);

            objectoutputstream.writeObject(firstperson);
            objectoutputstream.writeObject(secondperson);
            objectoutputstream.writeObject(book);

            objectoutputstream.flush();
            objectoutputstream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        new ObjectOutputStreamDemo();
    }
}

مشابه کد قبلی است با این تفاوت که این بار دو شی از کلاس Person و یک شی از کلاس Book در فایل نوشتیم. کد خواندن شی از فایل را به صورت زیر تغییر می دهیم :

import java.io.*;

public class ObjectInputStreamDemo
{
    public ObjectInputStreamDemo()
    {
        File myFile = new File("G:/Test.obj");
        FileInputStream fileinputstream = null;
        ObjectInputStream objectinputstream = null;

        try
        {
            fileinputstream = new FileInputStream(myFile);
            objectinputstream = new ObjectInputStream(fileinputstream);

            Person firstperson = (Person)objectinputstream.readObject();

            Person secondperson = (Person)objectinputstream.readObject();

            Book book = (Book)objectinputstream.readObject();

            System.out.println(firstperson);
            System.out.println(secondperson);
            System.out.println(book);

            objectinputstream.close();
        }
        catch (IOException | ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
    }
    public static void main(String[] args)
    {
        new ObjectInputStreamDemo();
    }
}

این کد نیز بسیار مشابه کد خواندن شی از فایل قبلی است ، تنها نکته مهم این است که اشیا به همان ترتیبی که در فایل نوشته شده اند باید از فایل خوانده شوند. خروجی کد بالا به صورت زیر خواهد بود :

[John : Scith , 15]
[Jason : Obimiang , 20]
( Core Java , 400 )