본문 바로가기
java/개념

문자 스트림과 파일 입출력

by unhyepnhj 2024. 6. 19.

문자 스트림 클래스

- 문자 스트림은 2바이트의 유니코드 문자를 단위로 입출력

- 문자화되지 않는 바이너리 정보(ex: 이미지)들은 문자 스트림 클래스에서 처리 불가

※ 바이너리 코드: 컴퓨터가 이해할 수 있는 이진코드(0과 1로 구성)

    바이트 코드: 가상 머신(VM)이 이해할 수 있는 이진코드 

 

- 문자 입력 스트림은 바이트들을 전달받고 이 바이트들을 '로컬 문자 집합'에 있는 문자인지 비교하여 문자로 변환

- 로컬 문자 집합에서 찾을 수 없는 경우 문자가 아니거나 문자 집합이 잘못 설정되어 있는 경우임

 

FileReader 생성자

 

FileReader, Reader, InputStreamReader의 공통 주요 메소드


FileReader를 이용한 텍스트 파일 읽기

 

파일 입력 스트림 생성

FileReader fin = new FileReader("c:\\text.txt");
//FileReader로 파일 입력 스트림을 생성하고 c:\\test.txt 파일을 연결하는 코드

- FileReader의 생성자는 c:\test.txt 파일을 찾아 열고 파일과 스트림을 연결

- 이때 c:\test.txt 파일은 문자들로만 구성된 텍스트 파일 

 

파일 읽기

int c;
while((c=fin.read())!=-1){		//문자 하나를 c에 읽어들임
	System.out.println((char)c);	//c를 화면에 출력
}

- fin.read()는 연결된 파일로부터 문자 하나를 읽어 리턴

- 파일의 끝(EOF, End Of File)을 만나면 -1을 리턴

 

※ 문자를 읽어들이는 데 char이 아닌 int 타입 변수를 사용하는 이유

- char로 리턴받게 되면 0xFF를 리턴하므로 EOF 처리 불가

- int로 0xFFFFFFFF를 리턴받아 강제 타입 변환

char[] buf = new char[1024];	//1KB
int n = fin.read(buf);		//한 번에 1024개의 문자를 읽어 buf[]에 저장하고 실제 읽은 문자 수 리턴

- 파일이 큰 경우 한 번에 한 문자씩 읽으면 읽는 속도가 느림

- 한 번에 한 블록(버퍼 크기)만큼 읽는 read() 사용

- 파일에 남아 있는 문자의 개수가 1024개보다 작을 때, read()는 실제로 읽은 문자의 개수를 리턴

 

※ 버퍼란?

읽고 쓸 데이터를 저장하는 배열

 

스트림 닫기

fin.close();

- 파일 읽기가 더 이상 필요 없으면 close() 메소드를 호출하여 입력 스트림을 닫음

- 닫힌 스트림으로부터는 더 이상 읽을 수 없음


파일 입출력과 예외 처리

 

1. 파일 경로명이 틀린 경우

- FileReader 생성자는 FileNotFoundException을 발생시킴

FileReader fn = new FileReader("c:\\test.txt");	//FileNotFoundException 발생 가능

 

2. 파일 읽기, 쓰기, 닫기를 하는 동안 입출력 오류 발생

- read(), write(), close() 메소드는 IOException 예외 발생

int c = fin.read();	//IOException 발생 가능

 

>> try-catch 블록 필요

try{
	FileReader fin = new FileReader("c:\\test.txt");
    ...
    int c = fin.read();
    ...
    fin.close();
} catch(FileNotFoundException e){
	System.out.println("파일을 열 수 없음");	//생략 가능
} catch(IOException e){
	System.out.println("입출력 오류");
}

- FileNotFoundException은 IOException을 상속받으므로 catch(IOException e){ }문만 있어도 무방


문자 집합과 InputStreamReader를 이용한 텍스트 파일 읽기

- InputStreamReader는 스트림에 입력되는 바이트 데이터를 문자 집합을 통해 문자로 변환

- 이를 위해 InputStreamReader 생성자에 문자 집합 지정 필요

- 읽어들인 바이트들이 문자 집합에 속하지 않는 경우 해독할 수 없는 글자가 됨

 

InputStreamReader 생성자

 

1. InputStreamReader로 문자 입력 스트림 생성

- InputStreamReader는 바이트 스트림을 전달받아 문자 정보로 변환하는 스트림 객체

FileInputStream fin = new FileInputStream("c:\\Temp\\hangul.txt");

- 텍스트 파일을 읽기 위해 바이트 파일 입력 스트림 생성

InputStreamReader in = new InputStreamReader(fin, "MS949");
//fin으로부터 읽어 들인 바이트들을 문자로 인코딩하기 위한 문자 집합을 MS949에 저장

- InputStreamReader 객체 생성

- 윈도우에서 디폴트로 사용하는 문자 집합이 MS949이므로 InputStreamReader 생성자에 MS949 문자 집합을 생성

 

2. 파일 읽기

스트림이 연결된 모양

 

- in.read()는 문자 집합의 인코딩 규칙에 따라 fin에게 파일로부터 필요한 바이트들을 읽도록 지시

- 읽어 들인 바이트들이 MS949 문자 집합에 정의된 문자인지 찾아 한글 문자를 리턴

 

+

라고 교재에 나와 있어서 적기는 했는데 MS949로 인코딩하면 오류가 납니다

MS949로 했을 때

 

MS949 대신 UTF-8을 사용해보세요

이제 보니 메모장에도 UTF-8로 돼 있네요(우측 하단)

fin=new FileInputStream("c:\\Temp\\hangul.txt");
in=new InputStreamReader(fin, "UTF8");
int c;

FileWriter를 이용한 텍스트 파일 쓰기

 

FileWriter와 OutputStreamWriter 생성자

 

FileWriter와 OutputStreamWriter 주요 메소드


예제 8-1 FileReader를 이용하여 c:\windows\system.ini 파일을 읽어 화면에 출력하는 프로그램 작성

import java.io.*;

public class FileReaderEx {
	public static void main(String[] args) {
		FileReader fin=null;
		try {
			fin=new FileReader("c:\\windows\\system.ini");
			int c;
			while((c=fin.read())!=-1) {
				System.out.print((char)c);
			}
			fin.close();
		}
		catch(IOException e) {
			System.out.println("입출력 오류");
		}
	}
}

 

>> 실행

 

예제 8-2 InputStreamReader을 이용하여 MS949 문자 집합으로 한글 텍스트 파일을 일고 출력

※ Temp 폴더에 hangul.txt 파일이 미리 작성되어 있어야 함

 

저는 UTF8로 했어요

import java. io.*;

public class FileReadHangulSuccess {
	public static void main(String[] args) {
		InputStreamReader in=null;
		FileInputStream fin=null;
		
		try {
			fin=new FileInputStream("c:\\Temp\\hangul.txt");
			in=new InputStreamReader(fin, "UTF8");
			int c;
			
			System.out.println("인코딩 문자 집합은 "+in.getEncoding());	//문자 집합 이름 리턴
			while((c=in.read())!=-1){
				System.out.print((char)c);
			}
			in.close();
			fin.close();
		}
		catch(IOException e) {
			System.out.println("입출력 오류");
		}
	}
}

 

>>실행

 

예제 8-3 InputStreamReader의 문자 집합을 US-ASCII로 지정하여 한글 파일을 읽고 출력

- 문자 집합 지정이 잘못된 예

import java.io.*;

public class FileReadingHangulFail {

	public static void main(String[] args) {
		InputStreamReader in=null;
		FileInputStream fin=null;
		try {
			fin=new FileInputStream("c:\\Temp\\hangul.txt");
			in=new InputStreamReader(fin, "US-ASCII");
			int c;
			
			System.out.println("인코딩 문자 집합은 "+in.getEncoding());
			while((c=in.read())!=-1){
				System.out.print((char)c);
			}
			in.close();
			fin.close();
		}
			catch(IOException e){
				System.out.println("입출력 오류");
			}
	}
}

 

>> 실행

 

예제 8-4 Scanner를 이용하여 입력받은 데이터를 c:\Temp\test.txt 파일에 저장하는 프로그램 작성

import java.util.*;
import java.io.*;

public class FileWriterEx {
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		FileWriter fout=null;
		int c;
		try {
			fout=new FileWriter("c:\\Temp\\test.txt");
			while(true) {
				String line=scanner.nextLine();
				if(line.length()==0) break;
				fout.write(line, 0, line.length());		//읽은 문자열 파일에 저장
				fout.write("\r\n", 0, 2);		//줄바꿈
			}
			fout.close();
		}
		catch(IOException e) {
			System.out.println("입출력 오류");
		}
		scanner.close();
	}
}

 

>>실행

이렇게 입력하면

Temp 폴더에 test.txt 파일이 생성되고 입력한 내용 저장

'java > 개념' 카테고리의 다른 글

버퍼 입출력과 파일 입출력  (0) 2024.06.23
바이트 스트림과 파일 입출력  (0) 2024.06.20
입출력 스트림  (0) 2024.06.19
제네릭과 배열  (0) 2024.06.10
제네릭 만들기  (0) 2024.06.10