java

[java/기본] 입력과 출력

tea-tea 2024. 4. 21. 19:10

자바에서는 파일이나 콘솔의 입력과 출력을 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