컴퓨터공학 💻 도서관📚

Part2. 6-14 바이트 단위 입출력 스트림 본문

✅🌲강의 복습 노트/패캠 JavaSpring 강의,코드 복습

Part2. 6-14 바이트 단위 입출력 스트림

들판속초록풀 2025. 8. 22. 17:14

여기서는 주로 파일 입출력을 얘기한다고 한다. 

가장 많이 사용하는 입출력 중 하나가 파일이다.

그래서 파일에서 어떻게 입력이 일어나고, 어떻게 출력을 하는지 살펴본다고 한다.

 

InputStream

  • '바이트 단위 입력 스트림' 최상위 추상 클래스
  • InputStream에 많은 추상 메서드가 선언되어 있고 이를 하위 스트림이 상속받아 구현함
  • 주요 하위 클래스

 

  • 주요 메서드

read() : 한 바이트 읽어라

readf(byte b[]) :  byte array 크기만큼 읽어라

read(byte b[], int off, int len) :  b[] 크기의 자료를 b[off] 부터 len 만큼 읽어라

close :  스트림은 반드시 close를 해야 하는데
과거 강의에서 말했듯 OutoCloseable 인터페이스를 임플피멘테이션 한 경우는 close가 자동으로 불린다
그래서 이 메서드는 명시적으로 안 부르는 경우가 요새는 많이 있다.
(표준 입출력 : System.in, out 은 close 안 해도 된다 ,  파일이나 다른 얘들을 한다.)

 

FileInputStream 예제

  • 파일에서 한 바이트씩 자료 읽기
public class FileInputStreamTest1 {

	public static void main(String[] args) {
		FileInputStream fis = null;
		
		try {
			fis = new FileInputStream("input.txt");
		
			System.out.println((char)fis.read());   // read() 1번
			System.out.println((char)fis.read());
			System.out.println((char)fis.read());
		
		} catch (IOException e) {  // IoException 이 FileNotFoundException 의 상위 익셉션이어서 이렇게 함 : 이렇게 하면 try 안에 있는 IoExceptino은 모두 여기 걸림
			System.out.println(e);
		} finally{       // finally 는 오류가 있든 없든 무조건 실행된다.
			try {
				fis.close();
			} catch (IOException e) {
				System.out.println(e);
			} catch (NullPointerException e){   // NULL 이면 close 하면 안 되서(오류 남) 예외처리 꼭 해줘야 한다.
				System.out.println(e);     // NullPointerException 이 기억이 안 나면 그냥 Exception e3 이렇게 최상위로 선언하면 된다.
			}
		}
		System.out.println("end");
	}

}
  • 파일의 끝까지 한 바이트씩 자료 읽기
public class FileInputStreamTest2 {

	public static void main(String[] args) {

		try(FileInputStream fis = new FileInputStream("input.txt")){  // try () 안에 리소스를 넣으면 AutoClose 되는데 해당 리소소 클래스가 AutoCloseable 인페를 구현해야 한다.
			int i;
			while ( (i = fis.read()) != -1){   // 반복문으로 파일의 끝(-1 반환)까지 보게 한다.
				System.out.println((char)i);
			}
			System.out.println("end");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

byte단위는 문자 핸들링이 안 된다.
문자를 핸들링 하려면 File 같은 경우는 File-Reader가 제공이 되서 그걸 쓰거나
System.in 처럼  input.stream.reader 로 감싸서 할 수 도 있다.

 

 

  • 파일에서 바이트 배열로 자료 읽기 ( 배열에 남아 있는 자료가 있을 수 있음에 유의 )
public class FileInputStreamTest3 {

	public static void main(String[] args) {
		 		
		try (FileInputStream fis = new FileInputStream("input2.txt")){
			
			byte[] bs = new byte[10];
			int i;
			while ( (i = fis.read(bs)) != -1){     // read() 2번
				/*for(byte b : bs){
					System.out.print((char)b);
				}*/
				for(int k= 0; k<i; k++){     // 밑에 설명 있음
					System.out.print((char)bs[k]);
				}
				System.out.println(": " +i + "바이트 읽음" );
			}
			 
			/*while ( (i = fis.read(bs, 1, 9)) != -1){       밑에 설명 있음
				for(int k= 0; k<i; k++){
					System.out.print((char)bs[k]);
				}
				System.out.println(": " +i + "바이트 읽음" );
			}*/
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("end");
	}
}

// 출력
// ABCDEFGH  9바이트     밑에 설명 있음
// JKLMNOPQ  9바이트
// STUVWXY   8바이트

read(bs, 1, 9)를 하면   bs 안에는 이렇다  [ 0, A, B, C, D, E, F, G, H, I ]   (초기화값이 0인데  1번 인덱스부터 저장했다)

여기서 출력을 for(int k= 0; k<i; k++)   0부터 i-1까지 함 --> 즉, 인덱스 0~8까지 함 ( I 는 인덱스 9여서 출력 안 됨 )

그런데 bs[0] 에는 읽은 데이터가 없고 0임 --> 그래서 (char)0 은 화면에 보이지 않는다

그래서 화면에는 8개의 알파벳이 보이게 된다.  ABCDEFGH

 

1바이트로 다룰 수 있는 것 :  알파벳, 숫자, 특수문자

2~3 바이트로 다루는 것 :  한글, 일부 특수문자

 

 

for(int k= 0; k<i; k++)  이 코드에서 k<i 를 안 해주면  버퍼에 남아 있는 자료가 출력된다

 

 


OutputStream

  • 바이트 단위 출력 스트림 최상위 추상 클래스
  • 많은 추상 메서드가 선언되어 있고 이를 하위 스트림이 상속받아 구현함
  • 주요 하위 클래스

 

  • 주요 메서드

flush() 와 close() 메서드

  • 출력 버퍼를 비울때 flush() 메서드를 사용
    (우리가 출력을, write() 를 하면 바로바로 써지는게 아닌다.  출력 버퍼라는게 있는데
    특히 이제 소켓 같은 거를 쓰면, 네트워크를 하면 네트워크는 데이터 한 바이트 쓴다고 바로바로 날아가는 게 아니라,
    어느 정도 소켓이 사용하는 버퍼가 있고, 그 버퍼에,   출력용 버퍼에 데이터가 쌓이면, 한꺼번에 날아간다.
    그런데 데이터가 일정 부분 안 쌓이면 안 날아갈 수 도 있다 ,  출력이 일어나지 않을 수도 있다
    그래서 강제적으로 이때 버퍼를 비운다.
    화장실에서 물 내리는 걸 flushing 한다고 한다. 그래서 버퍼를 비우는, 강제적으로 비우게 하는게 flush이다.)
  • close() 메서드 내부에서 flush()가 호출되므로 close()메서드가 호출되면 출력 버퍼가 비워짐

FileOutputStream 예제

  • 파일에 한 바이트씩 쓰기
public class FileOutputStreamTest1 {

	public static void main(String[] args) {
		
		try(FileOutputStream fos = new FileOutputStream("output.txt")){  // 밑에 설명 있음
			fos.write(65);  //A
			fos.write(66);  //B
			fos.write(67);  //C
		}catch(IOException e) {
			e.printStackTrace();
		}
		System.out.println("출력이 완료되었습니다.");
	}
}

인풋 스트림은 읽으려는 파일이 없으면 FileNotFoundException 오류가 나는데
아웃풋 스트림은  파일이 없으면  파일을 만들어준다

 

아웃풋 스트림의 Default 는  Overwrite(덮어 쓰다)이다.
(내가 한 파일에 글을 다시 쓸 때 , 파일을 쓰고 닫았다가 다시 쓸 때 ,  다시 쓸려고 열어서 쓰면 처음부터 쓴다.)

(로그와 같이 뒤에 이어서 쓰고 싶으면  2번째 매개변수 자리에  true 라고 쓰면 된다.  FileOutputStream("output.txt", true)
2번째 매개변수인 Append 여부의 Default 는  false 이다.)

 

 

  • byte[ ] 배열에 A-Z 까지 넣고 배열을 한꺼번에 파일에 쓰기
public class FileOutputStreamTest2 {

	public static void main(String[] args) throws IOException {
		
		FileOutputStream fos = new FileOutputStream("output2.txt",true);
		try(fos){ //java 9 부터 제공되는 기능
		
			byte[] bs = new byte[26];
			byte data = 65;        //'A' 의 아스키 값
			for(int i = 0; i < bs.length; i++){  // A-Z 까지 배열에 넣기
				bs[i] = data;
				data++;
			}
			
			fos.write(bs);  //배열 한꺼번에 출력하기
		}catch(IOException e) {
			e.printStackTrace();
		}
		System.out.println("출력이 완료되었습니다.");
	}
}
  • byte[ ] 배열의 특정 위치에서 부터 정해진 길이 만큼 쓰기
public class FileOutputStreamTest3 {

	public static void main(String[] args) {
		 
		try(FileOutputStream fos = new FileOutputStream("output3.txt"))
		{
		
			byte[] bs = new byte[26];
			byte data = 65;     //'A' 의 아스키 값
			for(int i = 0; i < bs.length; i++){  // A-Z 까지 배열에 넣기
				bs[i] = data;
				data++;
			}
			fos.write(bs, 2, 10);   // 배열의 2 번째 위치부터 10 개 바이트 출력하기
		}catch(IOException e) {
			e.printStackTrace();
		}
		System.out.println("출력이 완료되었습니다.");
	}
}
Comments