[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

profile
기록하는 습관을 갖자

0개의 댓글