2018년 10월 2일 화요일

Java FileInputStream / BufferedReader의 스트림 출력 비교

이번에는 FileInputStream과 BufferedReader로 바이트단위를 출력할때 방법에 대해서 살펴보겠다.

1) 1바이트씩 출력하기
2) 한 줄씩 출력하기

위의 2가지경우가 있는데, 예제를 통해서 살펴보자
FileInputStream은 파일의 내용을 읽어오는데, 1바이트씩 문자를 읽어온다.
이와 다르게 BufferedReader는 파일(텍스트)을 한 줄씩(한 라인씩) 읽어서 값들을 출력 할 수 있다.

예제. 1바이트씩 출력한것과 한 줄(텍스트의 한 라인)씩 출력 소요시간 비교
  1. package org.java.project;
  2.  
  3. import java.io.BufferedInputStream;
  4. import java.io.BufferedReader;
  5. import java.io.FileInputStream;
  6. import java.io.FileNotFoundException;
  7. import java.io.IOException;
  8. import java.io.InputStreamReader;
  9. @FunctionalInterface
  10. interface ByteCodePrint{
  11.     public void ByteCodeFunc();
  12. }
  13. abstract class ByteCodes{
  14.     public static String FileReadPath = "data.txt";
  15.    
  16. }
  17. class ByteCodeExam extends ByteCodes {
  18.     public BufferedReader br;
  19.     public long startTime;
  20.     public long endTime;
  21.     public FileInputStream fis;
  22.    
  23.    
  24.     public ByteCodeExam() throws FileNotFoundException{
  25.         super();
  26.         this.fis = new FileInputStream(ByteCodes.FileReadPath);
  27.         this.br = new BufferedReader(new InputStreamReader(this.fis));
  28.     }
  29.     public void fileClose() {
  30.         if(this.fis != null)
  31.             try {
  32.                 this.fis.close();
  33.                 if(this.br != null)
  34.                     this.br.close();
  35.             } catch (IOException e) {
  36.                 // TODO Auto-generated catch block
  37.                 e.printStackTrace();
  38.             }
  39.        
  40.     }
  41.     ByteCodePrint LinePrint = ()  -> {
  42.         String reader = "";
  43.             try{
  44.                 this.startTime = System.currentTimeMillis();
  45.                 while((reader = this.br.readLine()) != null) {
  46.                     System.out.println(reader);
  47.                 }
  48.                 this.endTime = System.currentTimeMillis();
  49.                 System.out.println("LineBuffer의 소요된 시간 : " + (this.endTime - this.startTime) / 1000.0);
  50.             } catch (IOException e) {
  51.                 System.out.println(e.getMessage());
  52.             }
  53.     };
  54.     ByteCodePrint OneBytePrint = () -> {
  55.         try {
  56.             int reader = 0;
  57.             this.startTime = System.currentTimeMillis();
  58.             while( (reader = this.fis.read()) > 0) {
  59.                 System.out.print((char) reader);
  60.             }
  61.             this.endTime = System.currentTimeMillis();
  62.             System.out.println("\nOneByte의 소요된 시간 : " + (this.endTime - this.startTime) / 1000.0);
  63.         } catch( IOException  e) {
  64.             System.out.println(e.getMessage());
  65.         }
  66.     };
  67. }
  68. public class Compile{
  69.      public static void main(String[] args) {
  70.          try {
  71.             ByteCodeExam b = new ByteCodeExam();
  72.            
  73.             b.OneBytePrint.ByteCodeFunc(); // FileInputStream의 객체로 1Byte씩 출력하기
  74.             b.LinePrint.ByteCodeFunc();    // BufferReader의 객체로 한 줄씩 출력하기
  75.             b.fileClose();
  76.         } catch (FileNotFoundException e) {
  77.             System.out.println(e.getMessage());
  78.         }
  79.          
  80.      }
  81. }


실행결과
1) 1Byte씩 출력




2) 한 줄씩 출력















위의 소스코드는 한줄에 A~Z까지 차례대로 번갈아가면서 출력을하는데,
총 717줄까지 존재하며, 717줄까지 출력하는데 걸리는시간을 비교한 예제이다.

Buffer라는 메모리에 한 줄의 문자들을 전부 담아서 한줄씩 출력하는데 걸리는 시간이 더 짧았으며 이는 우리가 파일이나 네트워크상에서 입/출력 스트림을 처리할때에는 buffer를 사용한다면 더 효과적인 방법일것이라는 것을 설명하는 예제이다.

다음시간에는 DataInputStream에 대해서 살펴보도록하겠다.

2018년 10월 1일 월요일

java FileInputStream / FileOutputStream, FileReader / FileWriter

이전시간에 바이트 코드를 읽어오는 방법에 대해서 살펴보았다.
왜 바이트 코드를 읽어오는 방법에 대해 배우는걸까?

이전에 말했듯이 컴퓨터는 우리가 사용하는 문자를 이해할 수 없다. 
그래서 우리는 컴퓨터에게 저장시키는 문자를 당연하게 컴퓨터가 인식하는것 처럼 보이지만 실제로는 바이트 코드로 변환시켜서 컴퓨터가 이해할 수 있게하는것이다.

그러면 이 바이트 코드로 변환시켜주는 방법은 여러가지가 있는데,

그 중에서 ASCII코드, UTF-8, Unicode등의 인코딩을 통해서 실제 언어(영어, 한국어, 중국어 등 다른 국가들의 언어를 칭함)들을 파일에 읽고 쓰는것이 가능한것이다.

우선 우리는 파일 스트림이란 것에 대해서 배우면서 이러한 인코딩 방법들을 살펴보자

- JAVA의 FileInputStream / FileOutputStream
"파일 입/출력 스트림" 이란 말그대로 (텍스트)파일에 있는 저장된 텍스트로 된 것들 전부를(문자, 숫자, 특수기호 등) 읽기, 쓰기를 할때 바이트를 문자로 문자를 바이트로 즉, (파일에 관련된)스트림의 역할을 도와준다. 

자바에서는 InputStream클래스의 하위 클래스로써, 파일을 인스턴스화 즉, 파일객체라는것을 통해 접근이 가능하도록 도와준다. 

그럼 예제를 통해 살펴보자
먼저, Java Project폴더 경로에 output.txt라는 텍스트로 된 파일을 준비
텍스트의 내용은 1234 라는 숫자가 차례대로 적혀있다.

예제 1) output.txt파일의 내용을 한 바이트 단위로읽기

  1. package org.java.project;
  2.  
  3. import java.io.FileInputStream;
  4. import java.io.FileNotFoundException;
  5. import java.io.IOException;
  6.  
  7. public class Onebyte{
  8.     public static void main(String[] args) throws FileNotFoundException{
  9.         FileInputStream fis = new FileInputStream("output.txt");
  10.         int reader = 0;
  11.         try {
  12.             while((reader = fis.read()) >=0 ) {
  13.                     System.out.println(reader);
  14.             }
  15.         } catch (IOException e) {
  16.             // TODO Auto-generated catch block
  17.             e.printStackTrace();
  18.         }
  19.     }
  20. }

출력결과 : 49 50 51 52

: 정상적인 출력이다. 
파일의 내용은 1~4까지 차례대로 적혀있는데 왜 49~52라는 숫자가 나올까?
바로 컴퓨터는 아스키코드 값에 맞추어 저장하므로 바이트 코드로 정상출력이 된 것이다. 
(숫자는 1바이트로 아스키코드에는 48(0)~57(9)까지 저장이 되어있다.)

또 다른예제를 살펴보자.

예제 2) output.txt에 저장된 텍스트를 그대로 출력하기
  1. package org.java.project3.hanbat;
  2.  
  3. import java.io.FileNotFoundException;
  4. import java.io.FileReader;
  5. import java.io.IOException;
  6.  
  7. public class Onebyte {
  8.     public static void main(String[] args) throws FileNotFoundException, IOException {
  9.         FileReader fr = new FileReader("output.txt");
  10.         int reader = 0;
  11.         while((reader = fr.read()) >= 0)
  12.             System.out.println((char)reader);
  13.     }
  14. }

출력결과 : 1 2 3 4

위의 FileInputStream과 아래의 FileReader가 보일것이다.
- FIleInputStream, FileOutputStream
- FileReader, FileWriter 이들은 모두 파일을 읽고 쓰기가 가능하다. 하지만 상속하는 부모의  클래스가 다르다.
- FileInputStream / FileOutputStream은  InputStream과 OutputStream을 상속받음.
- FileReader / FileWriter는 Reader와 Writer를 상속받는다.

그리고 FileInputStream / FileOutputStream은 텍스트의 내용을 바이트 단위로 읽어서 
1바이트인 숫자, 문자로 형변환해서 출력할 수 있으나, 1바이트가 넘어가는경우 버퍼라는 공간에 데이터를 입력받아서 출력해야한다.

하지만, FileReader와 FileWriter는 1바이트 이상 한글도 출력이 가능하다.

다음시간에는 FileInputStream . FileOutputStream클래스로 바이트 단위들을 사용하는 방법 대해서 자세히 살펴보도록하자 

2018년 9월 23일 일요일

Java 문자를 ASCII코드로 표현하기

이번시간에는 Java에서 아스키코드를 사용하는 방법에 대해서 살펴보겠다.

그전에 한가지 스트림이라는 지식에 대해 살펴보고 진행하자.

우리가 작성하는 문자들은 데이터들은 컴퓨터가 문자하나하나를 인식할 수 있을까?
다음의 예를 살펴보자.

 - Stream과정

① 'h'라는 문자를 키보드 클릭 → ②운영체제(OS)에 전달(동작 : 사용자가 키보드 'h' 클릭) → ③메모장에 'h'라는 문자를 보여줌

이 과정에서 컴퓨터가 h라는 데이터를 입력받은것을 어떻게 인식할 수 있을까?
바로 이 문자 h라는 것을 컴퓨터가 이해할 수 있도록 바이트단위로 변환시킨뒤 데이터가 전달되는 것이다. (Input Stream)
그리고 컴퓨터는 이것을 다시 사용자들이 인식할 수 있도록 바이트 단위로 표현된 문자를  원래의 값으로 변환시킨뒤 메모장 'h'라는 문자를 보이도록 하는 것이다.

즉, 입력/출력하는(InputStream / OutputStream) 동안에 컴퓨터들에게는 바이트 단위로 문자를 인식시키는것이다. 컴퓨터는 0과 1밖에 모르기 때문이다.
그리고 바이트 단위 → 문자형, 문자형 → 바이트 단위로 바꿔주는 것을 인코딩이라고 하며, 이 인코딩하는 다양한 방식들이 존재한다.
- 대표적으로 ASCII, Unicode, UTF-8 등이 있다.

- java에서 문자를 바이트 단위로 표현하기

예제 1) 문자와 숫자를 바이트 단위로 저장한 뒤 출력하기.
  1. package org.java.project;
  2.  
  3. public class Onebyte{
  4.     public static void main(String[] args) {
  5.  
  6.         byte byte_a = 'a';
  7.         byte byte_b = 'b';
  8.        
  9.         byte byte_A = 'A';
  10.         byte byte_B = 'B';
  11.        
  12.         byte byte_0 = '0';
  13.         byte byte_9 = '9';
  14.         System.out.println("문자 a를 바이트 단위로 표현 : " + byte_a);
  15.         System.out.println("문자 b를 바이트 단위로 표현 : " + byte_b);
  16.         System.out.print("\n");
  17.         System.out.println("문자 A를 바이트 단위로 표현 : " + byte_A);
  18.         System.out.println("문자 B를 바이트 단위로 표현 : " + byte_B);
  19.         System.out.print("\n");
  20.         System.out.println("숫자 0을 바이트 단위로 표현 : " + byte_0);
  21.         System.out.println("숫자 9를 바이트 단위로 표현 : " + byte_9);
  22.     }
  23. }
▶실행결과











: 실행결과 인코딩방식은 ASCII이며, 문자와 숫자가 해당하는 ASCII코드표에 있는 값의 데이터를 출력한다. 그래서 숫자로 입력받은 값 byte_0과 byte_9는 사실 숫자가 아닌 문자 '0', 문자 '9'로 인식하여 아스키 코드표에 해당하는 값 0~9는 아스키코드표에서 48~57에 으로 저장한다.
0을 아스키코드값 : 48( 48 : 2진수 0011 0000으로 컴퓨터가 인식)
9를 아스키코드값 : 57( 57 : 2진수 0011 1001으로 컴퓨터가 인식)

예제 2) 한문자씩 바이트코드 데이터형의 배열에 저장한 뒤 출력방법 - 1
  1. package org.java.project3.hanbat;
  2.  
  3. public class Onebyte{
  4.     public static void main(String[] args) {
  5.        
  6.         String str = "Hello world";
  7.         int j = 0;
  8.        
  9.         byte[] byte_str = new byte[str.length()]; // 문자열 갯수만큼 바이트코드로 인식함.
  10.        
  11.         // 문자열의 한문자씩 byte단위로 byte배열 byte_str에 저장하기.
  12.         for(int i = 0; i < str.length(); i++)
  13.             byte_str[i] = (byte)str.charAt(i); //바이트의 단위로 인식할 수 있게 형변환.
  14.        
  15.         // 자료형 문자, byte단위의 문자 비교하기  
  16.         for(byte value : byte_str)
  17.             System.out.println(str.charAt(j++) + " : " + value);       
  18.     }
  19. }
▶실행결과




















예제 3) 문자열을 바이트코드로 인코딩한뒤 바이트코드를 문자열로 디코딩하기
  1. package org.java.project;
  2. public class Onebyte{
  3.     public static void main(String[] args) {
  4.         String Text = "Hello World";
  5.         byte[] byteText = Text.getBytes(); // 문자열을 바이트코드로 변환시켜서 배열 하나하나에 저장시킴.
  6.        
  7.         System.out.println("---문자열과, 바이트코드로 인코딩한 결과---");
  8.         System.out.println("Text : " + Text);
  9.         System.out.println("byte_Text : " + byteText); // 바이트코드로 인코딩한 배열의 주소를 출력하고있음.
  10.         System.out.println("byte_Text.toString() : " + byteText.toString());
  11.        
  12.         System.out.println("\r---문자를 바이트코드로 표현한 결과---");
  13.         for(int i=0; i<Text.length(); i++)
  14.             System.out.println("Character [" + Text.charAt(i) + "] To ASCII Code : " + byteText[i]);
  15.        
  16.         String byteToText = new String(byteText);
  17.         System.out.println("\r---바이트코드에서 문자열로 디코딩한 결과---");
  18.         System.out.println(byteToText);
  19.     }  
  20. }
▶실행결과




















이로써 자바에서는 문자에서 바이트코드로 인코딩할때 8bit로 2의 7승까지 표현 할 수 있는 ASCII방식을 사용한다는 것을 살펴보았다.

[Java] N-I/O(Non-Blocking) 파일 읽기 쓰기 - GatheringByteChannel, ScatteringByteChannel, ByteBuffer 사용.

우리는 지금까지 다음과 같이 살펴보았다. 1.  InputStream / OutputStream : 입, 출력 스트림을 바이트로 처리하여 읽기, 쓰기. 2.  FileInputStream / FileOutputStream : 입, 출력 스트림을 ...