공적's life

4-1 I.O and File 본문

Programing/Java programing

4-1 I.O and File

melpis 2010. 7. 31. 02:07

이제 우리가 배워야 할 내용은 가장 기본적인 IO입니다. 일단은

 

이전에 배웠던 문서 관리에서 살짝 맛보기로 사용된 적이 있었죠?

 

이제 그것을 조금 더 심화 해서 해보겠습니다. 이것이 끝나면 File을 할 것이고.

 

그리고 나서 network쪽을 한 후에 간단한 WebServer 만들어 본 후에 그리고 나서

 

시간적 여유가 있으면 DBMS를 만들어 보도록 하죠. 물론 풀로 구현하는 것이 아니라

 

맛보기 구현 정보만 할 것입니다.

 

일단 간단한 예제를 보면서 이해 해보도록 하죠.

 

일단 가장 기본이 되는 표준 입출력을 해볼까요?

 

public class InputStreamExercise {

 

    public static void main(String[] args) throws IOException {

        //표준 입력

        InputStream inputStream = System.in;

        

        int read=inputStream.read();

        

        //표준 출력

        OutputStream outputStream = System.out;

        //기록

        outputStream.write(read);

        //출력한다.

        outputStream.flush();

        

        

    }

    

}

컴퓨터는 문자를 입력 받아도 인식하지 못합니다. 그렇기 때문에 문자나 기호를 받으면 숫자로 변환하지요.

 

숫자도 우리가 쓰고 있는 십진수 즉 0~9까지 쓰는 것이 아니라 이진수 0과 1만 사용하는 숫자를 사용합니다.

 

뭐 간단히 말해서 전류가 흐르면 1 흐르지 않으면 0 이것이 바로 이진수 입니다.

 

그래서 위에서 read메소드를 호출하게 되면 반환값으로 0-255사이 값을 반환하게 됩니다.

 

이제 그것을 받아서 기록한 후에 flush란 메소드를 호출하게 되면 화면에 출력 되는 것입니다.

 

이것이 제일 간단하게 나타낸 것이네요. 파일 입출력도 역시 이와 비슷한 과정을 거쳐서 됩니다.

 

그럼 몇 가지 클래스들을 살펴볼까요?

 

제일 먼저 InputStream클래스를 살펴 보도록 하죠.

 

여기서 가장 중요한 메소드는 바로 read()란 메소드 입니다.

 

오버로딩 되어있는 메소드 입니다. 세가지로 사용 할 수 있군요.

 

첫 번째 read()는 설명 했으니 두 번째 read(byte[])를 설명해보죠.

 

이 메소드는 byte[]을 저장공간으로 활용하고. 그 값에 크기를 반환합니다.

 

세 번째 read (byte[] b, int off, int len) 두 번째 꺼와 마찬 가지로 byte[]를 저장공간으로

 

활용하고 int off는 시작점, int len 은 길이를 나타냅니다. 예제를 보면 쉽게 이해 하실 겁니다.

 

    //버퍼 설정

    byte[] buffer =new byte[4096];

    //읽기

    int readInputBuffer = inputStream.read(buffer);

    //얼마나 읽었는지 출력

    System.out.println(readInputBuffer);

    //무엇을 읽었는지 출력

    System.out.println(new String(buffer));

    //버퍼 초기화

    buffer =new byte[4096];

    //읽기 첫번째부터 읽고 2자만 읽기

    readInputBuffer= inputStream.read(buffer, 0, 2);

    //얼마나 읽었는지 출력

    System.out.println(readInputBuffer);

    //무엇을 읽었는지 출력

    System.out.println(new String(buffer));

 

참 간단하죠?

 

 

OutputStream의 write()란 메소드도 이와 똑같이 동작합니다.

 

 

그럼 전에 보았던 표준 입력에 대해서 다시 한번 살펴 볼까요?

 

    //표준 입력

    InputStream inputStream = System.in;

    

    InputStreamReader streamReader = new InputStreamReader(inputStream);

    

    BufferedReader bufferedReader = new BufferedReader(streamReader);

 

 

여기에는 어떠한 차이가 있을까요? 일단 InputStream과 InputStreamReader에 차이점을 살펴보죠.

 

서로 가지고 있는 메소드에서는 별 차이가 없습니다.

 

InputStream은 read메소드에 byte[]타입이 들어가고 InputStreamReader에는 char[]타입이 들어갑니다.

 

눈치 좋으신 분들은 한번에 눈치 채었죠? 바로 byte로 읽는가? Char로 읽는가의 차이입니다.

 

쉽게 말해서 숫자로 읽는가 아님 문자로 읽는가에 차이죠.

 

InputStreamReader는 또한 인코딩을 설정 할 수 있습니다. 컴퓨터에 쓰는 문자는 다 같아 보이지만

 

실은 전부 다른 문자 형식을 가지고 있습니다. 언어적 차이에 따라서 사용되는 문자수가 많거나

 

혹은 적거나 하기 때문에 이런 결과가 나왔습니다.

 

인코딩은 지금은 그다지 신경 쓸 필요는 없지만 나중에 웹 환경에 가면 살짝 신경 써줘야 합니다.

 

기본 원칙은 들어온 것을 그대로 내보낸다 입니다.

 

자 그름 마지막 남은 BufferdReader를 살펴볼까요? Reader란 것이 들어 간 것을 보아서

 

문자로 읽는 거 같습니다. Buffered란 단어 때문에 내부에 임시 저장 공간이 있다는 거 같습니다.

 

즉, 한번에 하나씩 읽는 것이 아니라 버퍼만큼 읽을 겁니다. 당연히 효율은 BufferedReader가 좋겠죠?

 

왜냐하면 한자씩 읽으면 그만큼 루프를 한번 더 도니까요.

 

OutputStream도 마찬가지 입니다. 대신에 Reader가 아닌 Writer라는 명칭이 붙었죠.

 

우리는 아직까지 byte와 char만 읽고 썼는데 여기가 끝이 아닙니다. 객체도 읽고 쓸 수 있죠.

 

이건 나중에 기회가 되면 해보도록 하고요. 이제 우리의 목표인 File을 읽고 써볼까요?

 

전에 만들어 놓았던 문서관리에 BoardDataBase부분만 수정하여 사용하도록 하죠.

 

코드를 보면서 이해하시는 것이 편 할거 같아서 설명은 생략합니다.

 

몇 가지 기억해야 할 것만 정리하죠.

 

첫째 Input,Output stream에서 다 썼으면 반드시 close()메소드를

 

호출해 주셔야 합니다. 왜냐하면 이 메소드를 호출하지 않고 사용하시면

 

아직 사용하는 것으로 인식하기 때문에 쓰기를 할 수가 없죠. 읽기도 마찬가지고요.

 

둘째 exists() 메소드를 사용해서 존재 여부를 판단하세요.

 

혹시 권한 때문에 파일이 읽기거나 써지지 않는 경우도 있으니까

 

can종류에 메소드를 활용해 보세요.

 

윈도우에서는 별로 문제가 되지 않지만 리눅스나 유닉스 기반 시스템들은

 

파일에 권한을 줄 수 있습니다. 읽기 쓰기 실행 이렇게요.

 

그러니까 반드시 체크하셔야 합니다

 

이상입니다.

 

삭제에서 많이 고민했는데 내용자체를 수정을 못하겠더군요.

 

제가 아직 실력이 많이 부족한가 봅니다. ㅠ_ㅠ.

 

그럼 다음에는 바로 네트워크를 해보도록 하죠^^

 

 

package com.tistory.melpis.board;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class BoardDataBase {
	//경로
	private final static String path="c:/db/";
	//seq파일
	private final static String seqFile="seq";
	//db파일
	private final static String dbFile="db";

	public BoardDataBase() {
	}
	
	private int getSystemSeq(){
		// 결과값 반환 준비
		int returnSeq = 0;
		//1. 파일 읽기
		File seqDataFile = new File(path,seqFile);
		//2. 파일 존재 여부 판단
		if(!seqDataFile.exists()){
			try {
				//3. 없다면 파일생성
				seqDataFile.createNewFile();
				returnSeq= returnSeq+1;
				//4.기록
				FileOutputStream fos = new FileOutputStream(seqDataFile);
				fos.write(returnSeq);
				fos.flush();
				//5. 닫기
				fos.close();
				return returnSeq;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		try {
			//3. 있다면 파일읽기
			FileInputStream fis= new FileInputStream(seqDataFile);
			returnSeq=fis.read();
			fis.close();
			//4. 번호 증가후 기록
			returnSeq= returnSeq+1;
			FileOutputStream fos = new FileOutputStream(seqDataFile);
			fos.write(returnSeq);
			fos.flush();
			//5. 닫기
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return returnSeq;
	}
		
	//등록 (insert)
	public void insert(String title, String content){
		
		// 1. 문서 번호 가져오기
		int systemSeq = getSystemSeq();
		// 2. 등록일 가져오기
		Date systemDate = new Date();
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"yyyy.MM.dd HH:mm:ss", Locale.KOREA);
		String sysDate = dateFormat.format(systemDate);
		// 3. 조회수 입력
		int configHit = 0;
		
		// 4. 등록
		File dataFile = new File(path,dbFile);
		if(!dataFile.exists()){
			try {
				//5. 파일이 존재 하지 않으면 생성
				dataFile.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		FileWriter fw=null;
		try {
			//5. 존재하면 이어쓰기
			fw = new FileWriter(dataFile,true);
			fw.write("SEQ|"+String.valueOf(systemSeq)+",");
			fw.write("TITLE|"+title+",");
			fw.write("CONTENT|"+content+",");
			fw.write("REGIST_DATE|"+sysDate+",");
			fw.write("HIT|"+String.valueOf(configHit));
			fw.write("\n");
			fw.flush();
			//6. 닫기
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
				
		

	}
	
	// 한건 조회 (select)
	public Map select(int seq){
		//결과값 반환 준비
		Map returnResult = null;

		File file = new File(path,dbFile);
		try {
			//1. 파일 읽기
			FileReader fileReader = new FileReader(file);
			BufferedReader br = new BufferedReader(fileReader);
			String readLine = null;
			//2. 줄단위로 읽기
			while((readLine=br.readLine()) != null){
				String[] rows=readLine.split(",");
				String[] colums=rows[0].split("\\|");
				//3. seq가 일치하면 map에 담기
				if(colums[0].equals("SEQ") && colums[1].equals(String.valueOf(seq))){
					returnResult = new HashMap();
					for(String resultColums:rows){
						String []resultColum=resultColums.split("\\|");
						returnResult.put(resultColum[0], resultColum[1]);
					}	
					break;
				}
			}
			//4. 닫기
			br.close();
			fileReader.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return returnResult;
	}
	
	//여러건 조회 selectList
	public List> selectList(){
		//결과값 반환준비
		List> returnResult =  new ArrayList>();
		//1. 파일읽기
		File dataFile = new File(path,dbFile);
		FileReader fr = null;
		try {
			fr = new FileReader(dataFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		BufferedReader br = new BufferedReader(fr);
		try {
			String readLine= null;
			Map result=null;
			//2. 줄단위로 읽기
			while((readLine=br.readLine())!=null){
				String[] rows=readLine.split(",");
				result=new HashMap();
				//3. map에 담기
				for(String resultColums:rows){
					String []colums=resultColums.split("\\|");
					result.put(colums[0], colums[1]);
				}
				//4. 결과 값 list에 담기
				returnResult.add(result);
			}
			//5. 닫기
			br.close();
			fr.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return returnResult;
	}
	
	//삭제 (delete)
	public void delete(int seq){
		//1. 원래 파일 준비
		File dataFile = new File(path,dbFile);
		//2. 임시 파일 준비
		File tempFile = new File(path,"temp");
		
		FileWriter fw = null;
		BufferedWriter bw= null;
		//3. 임시 파일 생성
		if(!tempFile.exists()){
			try {
				tempFile.createNewFile();
				fw = new FileWriter(tempFile);
				bw = new BufferedWriter(fw);
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		try {
			FileReader fileReader = new FileReader(dataFile);
			BufferedReader br = new BufferedReader(fileReader);
			String readLine = null;
			//4. 원래 파일 줄단위로 읽기
			while((readLine=br.readLine()) != null){
				String[] rows=readLine.split(",");
				String[] colums=rows[0].split("\\|");
				//5. seq 일치 하지 않으면 temp파일에 쓰기
				if(!colums[1].equals(String.valueOf(seq))){
					bw.write(readLine);
					bw.newLine();
					bw.flush();
				}
				
			}
			//6. 닫기
			br.close();
			fileReader.close();
			bw.close();
			fw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//7. 기존 파일삭제
		dataFile.delete();
		//8. 임시 파일->기존파일 이름으로 변경
		tempFile.renameTo(dataFile);
		
	}
	//수정 (update)
	public void update(int seq,String title,String content){
		//1. 원래 파일 준비
		File dataFile = new File(path,dbFile);
		//2. 임시 파일 준비
		File tempFile = new File(path,"temp");
		//3. 시스템 시간 
		Date systemDate = new Date();
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"yyyy.MM.dd HH:mm:ss", Locale.KOREA);
		String sysDate = dateFormat.format(systemDate);
		//4. 임시파일 생성
		FileWriter fw = null;
		BufferedWriter bw= null;
		if(!tempFile.exists()){
			try {
				tempFile.createNewFile();
				fw = new FileWriter(tempFile);
				bw = new BufferedWriter(fw);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		try {
			FileReader fileReader = new FileReader(dataFile);
			BufferedReader br = new BufferedReader(fileReader);
			String readLine = null;
			//5. 줄단위로 읽기
			while((readLine=br.readLine()) != null){
				String[] rows=readLine.split(",");
				String[] colums=rows[0].split("\\|");
				//6. seq가 일치 하지 않을경우 임시파일에 기록 
				if(!colums[1].equals(String.valueOf(seq))){
					bw.write(readLine);
					bw.newLine();
					bw.flush();
				}else{
				//7. seq가 일치 할경우 새로운 내용으로 임시 파일에 기록
					String hit=rows[4].split("\\|")[1];
					bw.write("SEQ|"+String.valueOf(seq)+",");
					bw.write("TITLE|"+title+",");
					bw.write("CONTENT|"+content+",");
					bw.write("REGIST_DATE|"+sysDate+",");
					bw.write("HIT|"+hit);
					bw.newLine();
					bw.flush();
				}
				
			}
			//8. 닫기
			br.close();
			fileReader.close();
			bw.close();
			fw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//9. 기존 파일 삭제
		dataFile.delete();
		//10. 임시 파일->기존파일 이름으로 변경
		tempFile.renameTo(dataFile);
	}
}

'Programing > Java programing' 카테고리의 다른 글

4-3 DataBase network  (0) 2010.08.07
4-2 NetWork  (0) 2010.08.03
3-3 메소드, 클래스 분리 회고  (0) 2010.07.26
3-2 클래스로 분리  (0) 2010.07.25
3-1 메소드로 분리  (0) 2010.07.24