31 January 2013

เทียบความเร็วระหว่าง binary กับ text files

ผมมักจะแนะนำให้นักศึกษาเก็บข้อมูลแบบ binary (หรือที่เก็บไฟล์ แล้วเราจะเรียกมันว่า binary file) เวลาที่ต้องการความเร็วในการอ่านเขียนข้อมูล และลดพื้นที่ในการเก็บข้อมูล แม้ว่าจะมีข้อเสียอยู่อย่างหนึ่ง คือ เราเปิดดูข้อมูลใน binary file ได้ไม่สะดวกนัก ไม่สามารถเปิด text editor มาแก้ binary file ได้ง่ายๆ แบบ text file แต่บางครั้งผมก็สงสัยว่า ถ้าเปรียบเทียบความเร็วในการเขียนอ่านข้อมูลระหว่าง binary file กับ text file แล้ว จะต่างกันมากน้อยแค่ไหน ผมเลยลองเขียนโปรแกรม Java ง่ายๆ ขึ้นมาทดลองดู ให้โปรแกรมสร้างไฟล์เก็บข้อมูล double จำนวน 10,000,000 ตัวลองไฟล์สองแบบ แล้วลองอ่านขึ้นมาดูว่าใช้เวลาต่างกันแค่ไหน

package org.cholwich.binvstxt;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class BinVsTxt {
  
  public void writeTextFile(String fname, int N) {
    try {
      Random r = new Random();
      r.setSeed(10241024);
      PrintWriter out = new PrintWriter(new FileWriter(fname));
      for(int i=0; i<N; i++) {
        out.println(r.nextDouble());
      }
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  
  public void writeBinaryFile(String fname, int N) {
    try {
      Random r = new Random();
      r.setSeed(10241024);
      DataOutputStream out = new DataOutputStream(
                                new BufferedOutputStream(
                                    new FileOutputStream(fname)));
      for(int i=0; i<N; i++) {
        out.writeDouble(r.nextDouble());
      }
      out.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  
  public List<Double> readTextFile(String fname) {
    List<Double> l = new ArrayList<Double>(); 
    try {
      BufferedReader in = new BufferedReader(
                            new FileReader(fname));
      double d;
      String buf;
      while((buf = in.readLine()) != null) {
        d = Double.parseDouble(buf);
        l.add(d);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (NumberFormatException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return l;
  }

  public List<Double> readBinaryFile(String fname) {
    List<Double> l = new ArrayList<Double>();
    DataInputStream in = null;
    try {
      in = new DataInputStream(
                new BufferedInputStream(
                    new FileInputStream(fname)));
      double d;
      while(true) {
        d = in.readDouble();
        l.add(d);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (EOFException e) {
      try {
        in.close();
      } catch (IOException e1) {
        e1.printStackTrace();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return l;
  }
  
  public static void main(String[] args) {
    boolean read = true;
    boolean bin = true;
    final int N = 10000000;
    
    for(String s : args) {
      if (s.equals("write")) {
        read = false;
      }
      else if (s.equals("text")) {
        bin = false;
      }
    }
    BinVsTxt m = new BinVsTxt();
    long start = System.currentTimeMillis();
    if (read) {
      if (bin) {
        List<Double> l = m.readBinaryFile("out"+N+".dat");
        System.out.println(l.get(N-1));
      }
      else {
        List<Double> l = m.readTextFile("out"+N+".txt");
        System.out.println(l.get(N-1));
      }
    }
    else {
      if (bin) {
        m.writeBinaryFile("out"+N+".dat", N);
      }
      else {
        m.writeTextFile("out"+N+".txt", N);
      }
    }
    long stop = System.currentTimeMillis();
    long len = stop - start;
    System.out.println("Required time = " + len);
  }
}

เมื่อลองรันทั้งสี่แบบดูแล้ว ปรากฎว่าความเร็วที่ได้คือ

  • เขียน text file ใช้เวลา 6.109 วินาที
  • อ่าน text file ใช้เวลา 11.666 วินาที
  • เขียน binary file ใช้เวลา 0.583 วินาที
  • อ่าน binary file ใช้เวลา 3.698 วินาที
จึงสรุปได้ว่า การใช้ binary file เร็วกว่าการใช้ text file พอสมควร แต่อาจจะไม่จำเป็นเท่าไหร่ ถ้าไม่ได้อ่านเขียนข้อมูลจำนวนมหาศาล

4 comments:

Nuke said...

สงสัยว่า parseDouble กินเวลาแค่ไหนครับ เห็นแบบ binary ไม่ต้อง parseDouble

Unknown said...

ผมคิดว่าสิ่งที่ต่างกัน คงเป็นที่ parseDouble แหละ

Unknown said...

เอาไว้จะลองจับเวลาดู

Anonymous said...

It's an amazing paragraph in support of all the internet visitors; they will obtain advantage from it I am sure.

my blog :: prase
my web page: molybdic