본문 바로가기

java

[java/기본] 입력과 출력

자바에서는 파일이나 콘솔의 입력과 출력을 stream이라는 개념을 통해 다룬다.

먼저 stream에 대해 알아보자.

 

stream


스트림은 완성된 데이터가 아니라 데이터의 흐름을 의미한다.

상당히 추상적인데, 예시를 들어보자.

"hello world"라는 데이터가 있다.

우리는 이 문자열 전체를 하나의 데이터로 간주하며 문장의 글자 하나하나, 혹은 바이트코드 한 단위 한 단위로 인식하지 않는다.

이는 배열이든 영상이든 마찬가지다. 하지만, 때때로 이런 데이터를 분해하여 연속적으로 받는 경우가 있다.

스트림은 이처럼 미완성 상태인 데이터를 연속으로 받는 과정을 의미한다.

 

스트림을 사용하는 이유는 다음과 같다.

첫 째, 스트림은 데이터의 순차적인 처리를 할 수 있는 내장 메소드를 제공한다. 마치 iterator의 커서처럼 말이다.

그 과정에서 데이터를 변환하거나 처리할 수 있다.

둘 째, 스트림은 크기를 가늠할 수 없는 입출력과 대용량 데이터를 처리할 때 유용하다.

 

 

InputStream, OutputStream


입출력에 사용되는 기본 추상 클래스.

1바이트 단위로 데이터를 전송한다.

 

구현 클래스 종류

FileInputStream, DataInputStream, BufferedInputStream

FileOutputStream, DataOutputStream, BufferedOutputStream

 

 

FileInputStream, FileOutputStream


기본적으로 1바이트씩 데이터를 처리한다.

 

 

FileInputStream.read();

인수가 없으면 1바이트씩 읽는다.

만약 읽을 데이터가 없으면 -1을 반환한다.

 

FileInputStream.read(byte[a]);

매개변수로 byte 배열 a크기를 주면 한번에 a만큼 읽는다.

영어는 글자당 1Byte인데, 한글은 한 글자당 3바이트다.
따라서 read(byte[])로 Byte배열에 잘못 넣으면 오버플로우가 발생한다.(Byte배열은 인덱스당 1바이트씩 저장함)

 

 

예시

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Main {
	public static void main(String[] args) {
		FileInputStream input = null;

		try {
			input = new FileInputStream("C:\\java\\statics\\original\\originalText.txt");

			while (true) {
				int data;
				data = input.read();
				if (data == -1)
					break;
				System.out.println((char) data);
                // 바이너리 코드로 읽은 데이터를 다시 인코딩함.
                // ASCII코드를 벗어나는 비알파펫 문자는 에러 발생. 추가 처리 필요
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {

			try {
				if (input != null)
					;
				input.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}
}

 

FileOutputStream(path)

path에 맞는 파일을 찾는다. 만약 못찾으면 새로 생성한다.

 

FileOutputStream.write(byte[] x);

x데이터 전체를 쓴다.

 

FileOutputStream.write(byte[] x, int start, int len);

x데이터를 start 시작점에서 len길이만큼 쓴다.

 

 

예시

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

public class Main {
	public static void main(String[] args) {
		OutputStream outputStream = null;

		try {

			outputStream = new FileOutputStream("C:\\java\\statics\\hello.txt");

			// 파일을 만들 위치와 이름을 설정함

			// 동일한 위치에 동일한 이름 및 확장자 파일이 있으면 덮어씀

			System.out.println(outputStream);

			String writeData = "i love java";

			byte[] arr = writeData.getBytes();

			// String.getBytes()

			// 문자열을 특정 인코딩 방식으로 인코딩된 바이트의 배열로 반환

			// 인코딩 방식은 정해져 있지 않으면 플랫폼의 기본 인코딩 방식 사용

			try {

				outputStream.write(arr, 0, arr.length);

				// outputStream.write(arr, 0, arr.length);

				// 스트림에 바이트 배열 첫인자를 0부터 arr.len 까지 가져와 입력함

				// 두 번째와 세 번째 인자 생략 가능

			} catch (Exception e) {

				e.printStackTrace();

			}

		} catch (FileNotFoundException e) {

			e.printStackTrace();

		} finally {

			System.out.println("finish");

			try {

				if (outputStream != null)

					outputStream.close();

			} catch (IOException e) {

				e.printStackTrace();

			}

		}
	}
}

 

 

응용: 파일 복사

while (true) {
int data = inputStream.read();
System.out.println(data);
if (data == -1)
break;
outputStream.write(data);
}

 

 

dataInputStream, dataOutputStream


fileStream이 데이터를 바이트 단위로 바꾸는 불편함이 있는 반면, 이건 문자열로 좀 더 편하게 다룰 수 있음.

다만, readUTF 같은 메소드들은 utf 문자열만 읽을 수 있는 것처럼 인코딩 오류가 발생할 수 있다.

(java.io.EOFException)

 

개인적으로는 사용했을 때 메모장에서 문자가 약간 틀어지는 문제 때문에 제대로 사용하지 못했다.

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

public class Main {
	public static void main(String[] args) {
		FileOutputStream output = null;
		String str ="하하gggㅎㅎ";
		DataOutputStream dataOutput=null;
		
		try {
			output = new FileOutputStream("C:\\java\\statics\\copy\\helloCopy.txt");
			dataOutput=new DataOutputStream(output);
			dataOutput.writeUTF(str);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			output.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}
}

 

bufferedReader, bufferedWriter