[TIL] 2021-02-17

pej4303·2021년 2월 16일
0

TIL

목록 보기
4/5
post-thumbnail

스트림(Stream) / 버퍼(Buffer) / 채널 (Channel) 기반의 I/O

  1. 스트림(Stream) 기반의 I/O
  • 단방향통신만 가능함 따라서 입력과 출력을 동시에 하려면 입력스트림, 출력스트림이 필요함
  • Queue 구조처럼 먼저 보낸 데이터를 먼저 받게됨(FIFO)
  • java.io 패키지에서 사용함
  1. 버퍼(Buffer) 기반의 I/O
  • 실제 데이터를 주고받는 스트림이 아니어서 입출력 할 수 없음
  • 스트림의 기능을 향상시키거나 다른 기능을 추가 할 수 있음
  • 기반 스트림을 먼저 생성한 다음에 이를 이용해서 보조 스트림을 생성해야 함
FileReader fReader = new FileReader("test.txt");    // 기반 스트림 생성
BufferedReader br = new BufferedReader(fReader);    // 보조 스트림 생성
...
br.read();
br.flush();
br.close();
  • FilterInputStream, FilterOutputStream은 모든 보조 스트림의 조상
  • 기반 스트림이 필요하기 때문에 단순히 기반 스트림의 메소드를 그대로 호출함
  • 기반스트림의 close(), flush()를 호출 할 필요없이 보조 스트림에 있는걸로 호출하기만 하면 됨
  1. 채널(Channel) 기반의 I/O
  • 양방향 입출력이 가능
  • 항상 버퍼를 이용해서 입출력을 함
  • java.nio 패키지에서 사용함

InputStream과 OutputStream

  1. InputStream
  • InputStream Class의 주요 메소드
    • read() : byte 단위로 데이터를 읽어오며(0~255 사이의 값) 데이터가 없으면 -1을 반환함
    • close() : 입력 스트림 자원을 닫음
    • available() : 읽어 올 수 있는 데이터의 크기를 반환함
    • skip() : 주어진 길이만큼 데이터를 건너뜀
    • mark() : 현재 위치를 표시해 놓음
    • reset() : 마지막으로 mark()가 호출되었던 위치로 되돌아감
  • markSuppoprted()을 통해서 mark(), reset()을 사용 할 수 있는 스트림인지 확인하고 사용해야 함
  1. OutputStream
  • OutputStream의 주요 메소드
    • write() : 데이터를 출력함
    • flush() : 버퍼에 있는 모든 출력 자원을 사용함
      (버퍼가 있는 출력스트림인 경우에만 의미가 있음)
    • close() : 출력 스트림 자원을 닫음

📌 프로그램 종료시 닫지 않은 스트림을 JVM이 자동적으로 닫아 주긴 하지만 반드시 다 사용한 후에는 close()를 호출해야 한다.
예외적으로 메모리를 사용하는 스트림과 표준 입출력 스트림은 따로 닫아주지 않아도 된다.


Byte와 Character 스트림

  1. Byte 스트림
  • 1Byte로 처리함
  • InputStream, OutputStream이 바이트기반 스트림의 조상
  • byte 배열을 이용

|구분|스트림|설명|
|:----:|:---|:---|
|바이트기반
스트림 | FileInputStream
FileOutputStream | 파일
|바이트기반
스트림 | CharArrayInputStream
CharArrayOutputStream | 메모리
|바이트기반
스트림 | PipedInputStream
PipedOutputStream | 프로세스
|바이트기반
스트림 | AudioInputStream
AudioOutputStream | 오디오장치
|바이트기반
보조스트림 | BufferedInputStream
BufferedOutputStream | 버퍼를 이용해서 입출력 향상
|바이트기반
보조스트림 | FilterInputStream
FilterOutputStream | 필터를 이용해서 입출력 향상
|바이트기반
보조스트림 | DataInputStream
DataOutputStream | 기본형 타입으로 데이터를 처리
|바이트기반
보조스트림 | SequenceInputStream | 두 개의 스트림을 하나로 연결
|바이트기반
보조스트림 | ObjectInputStream
ObjectOutputStream | 데이터를 객체 단위로 읽고 사용
|바이트기반
보조스트림 | PrintStream | 버퍼를 이용하여 추가적인 print 관련 기능이 있음
|바이트기반
보조스트림 | PushbackInputStream | 버퍼를 이용하여 읽어온 데이터를 다시 되돌리는 기능이 있음

출처 - Java의 정석

  1. Character 스트림
  • 문자 데이터를 이용할 때 사용
  • 바이트기반의 스트림으로 2Byte인 데이터를 처리하는데 어려움이 있어서 이를 보완하기 위해서 제공됨
  • 2Byte로 처리를 하며 유니코드간의 변환을 자동적으로 처리해 줌
  • Reader, Writer가 문자 스트림의 조상
  • char 배열을 이용

|구분|스트림|설명|
|:----:|:---|:---|
|문자기반
스트림|FileReader
FileWriter | 파일
|문자기반
스트림|CharArrayReader
CharArrayWriter|메모리
|문자기반
스트림|PipedReader
PipedWriter|프로세스
|문자기반
스트림|StringReader
StringWriter|문자열
|문자기반
보조스트림|BufferedReader
BufferedWriter| 버퍼를 이용해서 입출력 향상
|문자기반
보조스트림|FilterReader
FilterWriter|필터를 이용해서 입출력 향상
|문자기반
보조스트림|LinNumberReader|읽어 온 데이터의 줄번호를 카운트
|문자기반
보조스트림|PrintWriter|버퍼를 이용하며 추가적인 print관련 기능이 있음
|문자기반
보조스트림|PushbackReader|버퍼를 이용해서 읽어온 데이터를 다시 되돌리는 기능이 있음

출처 - Java의 정석


File Class

  • File 인스턴스는 파일 또는 디렉토리일수도 있음
  • File 인스턴스는 변경 할 수 없으며 일단 생성되면 File 객체의 경로는 절대로 변경되지 않음

|생성자|내용|
|-----------|---|
|File(String pathname) |주어진 파일명 또는 파일 경로로 File 인스턴스를 생성|
|File(String parent, String child) |파일 경로와 파일명을 따로 분리하여 File 인스턴스를 생성 할 수 있게함|
|File(File parent, String child) |파일 경로(File객체)와 파일명을 따로 분리하여 File 인스턴스를 생성 할 수 있게함|
|File(URI uri) |주어진 URI로 File 인스턴스를 생성|

출처 - https://docs.oracle.com/javase/8/docs/api/

  • OS마다 파일 경로 구분자, 파일명 구분자가 다르기 때문에 File class에는 static 변수를 이용하는 것이 좋음
// OS에 사용하는 경로 구분자를 반환( 윈도우 : ';' / 유닉스 :  ':' )
public static final char pathSeparatorChar = fs.getPathSeparator();
public static final String pathSeparator = "" + pathSeparatorChar;

// OS에 사용하는 이름 구분자를 반환( 윈도우 : '\' / 유닉스 :  '/' )
public static final char separatorChar = fs.getSeparator();
public static final String separator = "" + separatorChar;
System.out.println("## File.pathSeparator     = " + File.pathSeparator);
System.out.println("## File.pathSeparatorChar = " + File.pathSeparatorChar);

System.out.println("## File.separator         = " + File.separator);
System.out.println("## File.separatorChar     = " + File.separatorChar);

[ 실행결과 ]
## File.pathSeparator     = ;
## File.pathSeparatorChar = ;
## File.separator         = \
## File.separatorChar     = \

🔎 separatorChar와 pathSeparator 차이

  • 코드를 봐도 Char가 붙어있는건 앞에 공백이 있는 것 같음
  • 좀 더 찾아봐야 할 듯

파일 생성

  • File 인스턴스를 생성한다고 파일이 생성되는 것이 아님
    (File 인스턴스 생성 != 파일 생성)
  • createNewFile() : 빈 파일을 생성하지만 이미 생성되어 있으면 만들지 않음
// 1. 파일 경로만으로 File 인스턴스 생성
String filePath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13";

File file = new File(filePath);

System.out.println("## file.exists()       = " + file.exists());
System.out.println("## file.getPath()      = " + file.getPath());
System.out.println("============================================");

// 2. 파일 경로, 파일명으로  File 인스턴스 생성
String filePath2 = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\";
String fileName2 = "file2.txt";
File file2 = new File(filePath2, fileName2);

System.out.println("## file2.exists()      = " + file2.exists());
System.out.println("## file2.getPath()     = " + file2.getPath());
System.out.println("============================================");

// 3. 파일 경로+파일명으로  File 인스턴스 생성
String filefullPath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\file3.txt";
File file3 = new File(filefullPath);

// File 인스턴스 생성 != File 생성
// 파일명까지 넣은 경우 해당 위치에 파일이 있어야함
try {
    file3.createNewFile();
} catch (IOException e) {
    e.printStackTrace();
}

System.out.println("## file3.exists()      = " + file3.exists());
System.out.println("## file3.getPath()     = " + file3.getPath());
System.out.println("============================================");

[ 실행결과 ]
## file.exists()       = true
## file.getPath()      = D:\project\workspace\studyhalle\src\main\java\s1\week13
============================================
## file2.exists()      = false
## file2.getPath()     = D:\project\workspace\studyhalle\src\main\java\s1\week13\file2.txt
============================================
## file3.exists()      = true
## file3.getPath()     = D:\project\workspace\studyhalle\src\main\java\s1\week13\file3.txt
============================================

파일 쓰기

String fileFullPath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\writeFile.txt";
String str ="파일 쓰기 테스트 입니다!!";

try ( FileWriter fWriter = new FileWriter(fileFullPath); 
     BufferedWriter bw = new BufferedWriter(fWriter); ) {
   
   bw.write(str);
    
} catch (FileNotFoundException e) {
   e.printStackTrace();
} catch(IOException e){
   e.getStackTrace();
}

파일 읽기

String fileFullPath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\writeFile.txt";
        
try ( FileReader fReader = new FileReader(fileFullPath); 
      BufferedReader br = new BufferedReader(fReader); ) {
    String line = "";
    
    while ( (line = br.readLine()) != null ) {
        System.out.print(line);
    }
    
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch(IOException e){
    e.getStackTrace();
}

[ 실행결과 ]
파일 쓰기 테스트 입니다!!

📒 Reference

  • Java의 정석
  • https://docs.oracle.com/javase/8/docs/api/
  • https://sshkim.tistory.com/98
profile
기록하는 습관을 갖자

0개의 댓글