Please Enable JavaScript!
Gon[ Enable JavaScript ]

Java 파일입출력의 다양한 방법들을 배워본다

자바(JAVA)
반응형

Java 파일입출력의 다양한 방법들을 배워본다

 

개발환경 : JDK 1.6, eclipse indigo, window 7 32bit

 

개인적으로 만들어보고자 하는 안드로이드 프로그램의 아이디어가

갑자기 떠올라 이것저것 찾다보니 파일 입출력까지 흘러오게 되었다.

Java 에서는 아주 기본적인 내용이지만 웹 어플리케이션과 spring

프레임웍만 주구장창 다루다 보니 아주 잊어버린 것이다.

마침 나의 애마인 블러그를 찾아봐도 없는거 같아(확실치 않음 ㅋ) 

이참에 정리할 생각으로 작업하게 되었다.

 

방법을 크게 나누자면 2가지 인데 바이트 단위의 파일을 처리 하고자

할 때 FileInputStream, FileOutputStream 을 사용하고, 문자 단위의

파일을 처리하고자 할 때 FileReader, FileWriter 을 사용한다.

그러니까 1바이트씩 처리해야되는 경우에는 Stream 이 붙은

클래스를 사용하고 한글이나 문자 관련 처리를 원할때는 UTF-8

처리를 해야하기 때문에 Reader, Writer 가 붙은 클래스를

사용하는 것이 좋다. 그래야 추가 적인 처리를 하지 않아도 한글이

깨지지 않는다.

 

1. 입력과 출력스트림을 제어하는 FileInputStream, FileOutputStream 클래스

 

파일을 읽고 쓰는 클래스이며 읽을 때 파일이 존재하지 않으면

FileNotFoundException 예외를 발생시킨다.

파일을 쓸 때 경로가 일치하지 않으면 예외를 발생시키지 않고

파일을 생성하게 된다.

주석이 달려 있지만 간단하게 함수 별로 설명하자면 3가지는 읽기에 대한

방법들을 보여주는 것이고 나머지 2가지는 파일에 데이터를 쓸 때 옵션에

따라 이어쓸것인지 덮어 쓸것인지에 대한 내용이다.

 

FileInputStream 을 이용해서 파일의 내용을 읽는다 한 바이트씩 읽는 것이다

public static void FileStreamSample1() throws Exception {
	File f = new File("G:\\data.txt");
	if (f.exists()) {
		FileInputStream fis = new FileInputStream("a.bat");
		int i;
		while ((i = fis.read()) != -1) {
			System.out.print((char) i);
		}
		fis.close();
	} else {
		System.out.println("해당 파일이 없습니다.");
	}
}

바이트배열을 미리 준비해둔 상태에서 데이터를 읽고 준비한 바이트배열에

모두 채운다. 이 함수에 대해서는 조금 손볼 곳이 있긴 하지만 이런 것 이란 것만

파악하면 될 것 같다.

이렇게 하는 이유는 한글은 유니코드이기 때문에 2바이트가 필요하다. 위 처럼

1바이트만 읽어서 출력하면 한글일 경우 깨진다. 그걸 방지하기 위해서 예제 처럼

10 바이트를 채운후에 사용할려는 것이다.

 

public static void FileStreamSample2() throws Exception {
	FileInputStream fis = new FileInputStream("G:\\data.txt");
	int count;
	byte[] b = new byte[10];
	while ((count = fis.read(b)) != -1) {
		for (int i = 0; i < count; i++) {
			System.out.print((char) b[i]);
		}
	}
	fis.close();
}

 

읽을 내용만큼 바이트 배열을 미리 만든다. 파일의 내용을 읽어서 바이트 크기만큼

채우게 되면 프로그램이 끝나게 된다. 바이트 배열의 크기를 만들 때 짝수배값을

넣게 되면 한글이 깨질일이 없다.

public static void FileStreamSample3() throws Exception {
	String url = "G:\\data.txt";
	// 1.파이 사이즈 알아내기
	File f = new File(url);

	// int fileSize = (int) f.length();
	int fileSize = 200;
	System.out.println("파일의 사이즈:" + fileSize);

	// 2.파일 사이즈에 해당하는 배열 만들기
	byte[] b = new byte[fileSize];

	// 3.스트림을 이용해서 배열에 데이터 채우기
	FileInputStream fis = new FileInputStream(url);
	int pos = 0;
	int size = 10;
	int temp;
	while ((size = fis.read(b, pos, size)) > 0) {
		pos += size;
		temp = b.length - pos;
		if (temp < 10) {
			size = temp;
		}
	}
	fis.close();
	System.out.println("읽은 바이트 수:" + pos);

	// 4.배열을 통째로 파일에 기록하기
	FileOutputStream fos = new FileOutputStream("G:\\test.txt");
	fos.write(b);
	fos.close();
}

 

파일 쓰기이며 생성자 인자값을 안넘기므로 FileOutputStream 으로

파일 생성할 때 없으면 새로 만들고 있으면 덮어쓰게 된다

 

public static void FileStreamSample4() throws Exception {

		FileOutputStream stream = new FileOutputStream("D:\\data.txt");

		stream.write(101);
		stream.write(102);
		stream.write(103);

		stream.close(); // 스트림 닫기
	}

 

위소스와 달리 파일 생성자 두번째 인자로 true 를 넘긴다 .

그러면 파일을 쓸 때 기존에 값이 있으면 이어쓰기가 되는 것이다

 

public static void FileStreamSample5() throws Exception {
		FileOutputStream stream = new FileOutputStream("D:\\data.txt", true);

		stream.write(65);
		stream.write(66);
		stream.write(67);

		stream.close();
	}

2. 문자단위의 입력, 출력을 제어하는 FileReader, FileWriter 클래스

 

문자 스트림으로 한 문자씩 읽기 때문에 한글이 깨지는 현상은 없다.

파일을 읽을 때 존재하지 않으면 FileNotFoundException 예외를 발생시키며

파일을 쓸 때 경로가 존재하지 않으면 IOException 이 발생한다.

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReaderWriter {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			/** 파일 쓰기 */ 
			BufferedWriter writer = new BufferedWriter(new FileWriter("G:\\test.txt"));
			writer.write("파일쓰기 테스트\r\n");
			writer.write("다음라인");
			writer.newLine(); // \r\n 써도 되고 newLine 함수를 사용해 다음라인으로 내려도 된다

			writer.write("newLine 사용해서 내림\r\n");
			writer.close();

			/** 위에서 쓴 파일을 읽어들인다 */ 
			BufferedReader reader = new BufferedReader(new FileReader("G:\\test.txt"));
			String data = "";
			
			// readLine 사용해 한 라인씩 읽어들인다
			while ((data = reader.readLine()) != null) {
				System.out.println(data);
			}

			reader.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

3. 파일의 입출력을 중간에 버퍼를 둬서 성능을 향샹시킨 방법

 

클래스는 BufferedInputStream, BufferedOutputStream 이다.

1번과 2번처럼 파일을 읽고 쓰게 되면 매번 자원을 엑세스하기 때문에

상당한 부하가 있을 것이다. 그래서 read 함수를 호출하기 전에 버퍼의 크기 만큼

데이터를 채워진 상태에서 읽게 되면 그만큼 효율적이다.

아래 예제는 용량이 큰 이미지 파일을 스트림으로 읽어들여 성능을 비교한

내용이다.

 

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CompareBufferOrNotBuffer {

	public static void main(String args[]) {
		
		File source = new File("G:/GON1.jpg");
		File target1 = new File("G:/GON2.jpg");
		File target2 = new File("G:/GON3.jpg");

		// 버퍼링이 지원되지 않는 스트림
		FileInputStream fis = null;
		FileOutputStream fos = null;

		// 버퍼링이 지원되는 스트림
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;

		try {
			fis = new FileInputStream(source);
			fos = new FileOutputStream(target1);

			long startTime = System.currentTimeMillis();
			while (true) {
				int x = fis.read();
				if (x == -1) {
					break;
				}
				fos.write(x);
			}
			long endTime = System.currentTimeMillis() - startTime;
			System.out.println("일반 스트림: " + endTime);

			fis.close();
			fos.close();

			// 버퍼링 지원 스트림
			bis = new BufferedInputStream(new FileInputStream(source));
			bos = new BufferedOutputStream(new FileOutputStream(target2));

			startTime = System.currentTimeMillis();
			while (true) {
				int x = bis.read();
				if (x == -1) {
					break;
				}
				bos.write(x);
			}
			endTime = System.currentTimeMillis() - startTime;
			System.out.println("버퍼링 스트림: " + endTime);

			bis.close();
			bos.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace(); 
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

 

결과 값이다. 많은 차이가 나는 것을 볼수 있다

파일의 용량이 클수록 더 많은 차이가 날것이다

 

반응형
Posted by 녹두장군1
,