보통사람

[Study-13주차] I/O(입출력) 본문

Study

[Study-13주차] I/O(입출력)

pej4303 2021. 2. 12. 01:41
  • 목표

    • 자바의 Input과 Ontput에 대해 학습하세요.

  • 학습할 것(필수)

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

    • InputStream과 OutputStream

    • Byte와 Character 스트림

    • 표준 스트림 (System.in, System.out, System.err)

    • 파일 읽고 쓰기

 

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

 

1.1. 스트림(Stream) 기반의 I/O

  • 단방향통신만 가능함 따라서 입력과 출력을 동시에 하려면 입력스트림, 출력스트림이 필요함

  • Queue 구조처럼 먼저 보낸 데이터를 먼저 받게됨(FIFO)

  • java.io 패키지에서 사용함

1.2. 버퍼(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.3. 채널(Channel) 기반의 I/O

 

  • 양방향 입출력이 가능

  • 항상 버퍼를 이용해서 입출력을 함

  • java.nio 패키지에서 사용함

 

2. InputStream과 OutputStream

 

2.1. InputStream

 

  • InputStream Class의 주요 메소드

    • read() : byte 단위로 데이터를 읽어오며(0~255 사이의 값) 데이터가 없으면 -1을 반환함

    • close() : 입력 스트림 자원을 닫음

    • available() : 읽어 올 수 있는 데이터의 크기를 반환함

    • skip() : 주어진 길이만큼 데이터를 건너뜀

    • mark() : 현재 위치를 표시해 놓음

    • reset() : 마지막으로 mark()가 호출되었던 위치로 되돌아감

  • markSuppoprted()을 통해서 mark(), reset()을 사용 할 수 있는 스트림인지 확인하고 사용해야 함

2.2. OutputStream

 

  • OutputStream의 주요 메소드
    • write() : 데이터를 출력함

    • flush() : 버퍼에 있는 모든 출력 자원을 사용함(버퍼가 있는 출력스트림인 경우에만 의미가 있음)

    • close() : 출력 스트림 자원을 닫음

※  참조

  • 프로그램 종료시 닫지 않은 스트림을 JVM이 자동적으로 닫아 주긴 하지만 반드시 다 사용한 후에는 close()를 호출해야 한다.

  • 예외적으로 메모리를 사용하는 스트림과 표준 입출력 스트림은 따로 닫아주지 않아도 된다.

 

3. Byte와 Character 스트림

 

3.1.Byte 스트림

 

  • 1Byte로 처리함

  • InputStream, OutputStream이 바이트기반 스트림의 조상

  • byte 배열을 이용

출처 - Java의 정석

3.2. Character 스트림

 

  • 문자 데이터를 이용할 때 사용

  • 바이트기반의 스트림으로 2Byte인 데이터를 처리하는데 어려움이 있어서 이를 보완하기 위해서 제공됨

  • 2Byte로 처리를 하며 유니코드간의 변환을 자동적으로 처리해 줌

  • Reader, Writer가 문자 스트림의 조상

  • char 배열을 이용

출처 - Java의 정석

 

4. 표준 스트림 (System.in, System.out, System.err)

 

4.0. System Class

 

  • final 클래스로 상속 및 인스턴스를 만들 수 없음

public final class System {
...
}
  • 표준 입력, 표준 출력 및 오류 출력 스트림 기능이 있으며

    외부에서 정의된 속성 및 환경 변수에 대한 정보 제공,
    배열 일부를 빠르게 복사하기 위한 유틸리티 메소드가 있음
  • 별도의 스트림을 생성하는 코드를 작성하지 않아도 자동적으로 생성됨

4.1.  표준 입출력

 

  • System.in

    • 콘솔로부터 데이터를 입력받을 때 사용

    • 반환타입이 InputStream

public final static InputStream in = null;
  • System.out

    • 콘솔로 데이터를 출력할 때 사용

    • 반환타입이 PrintStream

public final static PrintStream out = null;
  • System.err

    • 콘솔로 오류 데이터를 출력할 때 사용

    • 반환타입이 PrintStream

public final static PrintStream err = null;

 

4.2. 표준입출력의 대상변경

 

  • setIn() : 표준 입력 스트림을 지정한 대상으로 재할당함

  • setOut() : 표준 출력 스트림을 지정한 대상으로 재할당함

  • setErr() : 표준 오류 출력 스트림을 지정한 대상으로 재할당함

PrintStream ps = null;
FileOutputStream output = null;
String filePath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\test.txt";

try {
    output = new FileOutputStream(filePath);
    ps = new PrintStream(output);
    System.setOut(ps);    // 출력대상을 파일로 변경
    
} catch (Exception e) {
    e.printStackTrace();
}

// System.out은 파일로 대상을 변경했기 때문에 System.err 내용만 나옴 
System.out.println("## System.out ##");
System.err.println("## System.err ##");

[ 실행결과 ]
## System.err ##

 

5. 파일 읽고 쓰기

 

5.0.  File Class

  • File 인스턴스는 파일 또는 디렉토리일수도 있음

  • File 인스턴스는 변경 할 수 없으며 일단 생성되면 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     = \

 

5.1. 파일 생성

  • 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
============================================

 

5.2. 파일 쓰기

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();
}

 

5.3. 파일 읽기

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();
}

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

 

5.4. RandomAccessFile

  • 하나의 클래스로 파일에 대한 입출력이 모두 가능함(DataInput, DataOutput 인터페이스를 모두 구현)

  • 기본 자료형 단위로 데이터를 입출력 할 수 있음

  • 내부적으로 파일포인터 때문에 파일의 어느 위치에서나 읽기, 쓰기가 가능함

int[] tmpArr = { 1, 10, 100, 1000, 2, 20, 200, 2000 };
        
// int배열의 데이터를 txt에 저장한 다음 출력함
String filePath = "D:\\project\\workspace\\studyhalle\\src\\main\\java\\s1\\week13\\testRandomAccess.txt";
String mode = "rw";

try {
    RandomAccessFile file = new RandomAccessFile(filePath, mode);
    for (int i=0; i<tmpArr.length; i++) {
        file.writeInt(tmpArr[i]);
    }
    
    file.seek(0);    // write()하면서 파일포인터가 마지막으로 이동했기때문에 포인터의 위치를 다시 처음으로 이동시킴
    
    // while(true) {
    // 아무것도 읽지 못하고 EOFException이 발생하는 것을 방지함
    while(file.length() != file.getFilePointer()) {
        System.out.println(file.readInt());
    }
    
} catch (Exception e) {
    e.printStackTrace();
}
  • testRandomAccess.txt 파일이 생성이 되지만 안의 내용은 알아 볼 수 없음

testRandomAccess.txt

 

※ 참조

 

 

Java Platform SE 8

 

docs.oracle.com

 

[Java] NIO 기반 입출력 및 네트워킹 - NIO, 파일 & 디렉토리

출처: http://palpit.tistory.com/640 1. NIO 소개  자바 4부터 새로운 입출력(NIO: New Input/Output)이라는 뜻에서 java.nio 패키지가 포함되었는데, 자바 7로 버전업하면서 자바 IO와 자바 NIO 사이의 일관성..

sshkim.tistory.com

 

'Study' 카테고리의 다른 글

[Study-14주차] 제네릭(Generics)  (0) 2021.02.23
[Study-12주차] 어노테이션(Annotation)  (0) 2021.01.31
[Study-11주차] Enum  (0) 2021.01.26
[Study-9주차] 예외 처리  (0) 2021.01.12
[Study-8주차] 인터페이스  (0) 2021.01.04