본문 바로가기
자바

[Java] 자바의 Input과 Output (입출력, i/o)

by 책 읽는 개발자_테드 2021. 9. 10.
반응형

학습목표

·  스트림 (Stream)기반의 IO 

·  Byte와 Character 스트림

   - Byte 스트림: InputStream, OutputStream

   - Character 스트림: Reader, Writer

·  InputStream과 OutputStream

·  표준 스트림 - System.in, System.out, System.err

·  파일 읽고 쓰기

     - File 클래스

     - FileInputStream

     - FileOutputStream

·  버퍼 (Buffer) / 채널 (Channel) 기반의 I/O


스트림 (Stream)기반의 IO

자바의 입력과 출력

·  자바에서는 데이터를 외부에서 읽고 다시 외부로 출력하는 작업(입출력)에 스트림(Stream)을 사용함

   - 스트림은 단일 방향으로 연속적으로 흘러가는 것을 말하며, 데이터는 출발지에서 나와 도착지로 들어간다는 개념

   - 스트리밍의 특성이 단방향이므로 하나의 스트림으로 입력과 출력을 모두 할 수 없음

   - 프로그램이 네트워크상의 다른 프로그램과 데이터 교환을 하기 위해서는 양쪽 모두 입력 스트림과 출력 스트림이 따로 필요

   - 입출력 작업의 예: 키보드, 파일, 네트워크에서 입력과 모니터, 파일, 네트워크의 출력 

 

· 프로그램이 출발지냐 또는 도착지냐에 따라서 스트림의 종류가 결정

   - 프로그램이 데이터를 입력받을 때는 입력 스트림(InputStream)

   - 프로그램이 데이터를 보낼 때는 출력 스트림(OutputStream)

 

·  자바에는 기본적인 데이터 입출력(IO: Input/Output) API를 제공하기 위한 java.io 패키지가 존재

https://velog.io/@ljs0429777/Java-IO

 

Byte 와 Character 스트림

· 스트림 클래스는 크게 두 종류, 바이트(byte) 기반 스트림과 문자(character) 기반 스트림으로 구분

· 바이트 기반 스트림: 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 주고 받을 수 있음

· 문자 기반 스트림: 오직 문자만 주고 받도록 특화

 

바이트 기반 스트림과 문자 기반 스트림은 최상위 클래스에 따라 다음과 같이 구분된다.

https://velog.io/@mingmang17/20.12.16

 

Byte 스트림 (InputStream과 OutputStream)

InputStream

· 바이트 기반 입력 스트림의 최상위 클래스로 추상 클래스

· 모든 바이트 기반 입력 스트림은 이 클래스를 상속

ex) FileInputStream, BufferedInputStream, DataInputStream 클래스

 

InputStream 클래스에 정의된 메소드

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=javainer&logNo=221479451489

 

read() 

· 입력 스트림으로부터 1바이트를 읽고 4바이트 int 타입으로 리턴

·  리턴된 4바이트 중 끝의 1바이트에만 데이터가 들어 있음

ex) 예를 들어 입력 스트림에서 5개의 바이트가 들어오면, read() 메소드로 1바이트씩 5번 읽을 수 있다.

· 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 -1을 리턴

   - 이것을 이용해서 읽을 수 있는 마지막 바이트까지 루프를 돌며 한 바이트씩 읽을 수 있음

 

▶ 예시 - 파일 끝까지 읽기

InputStream is = new FileInputStream("C://test.jpg");
int readByte;

while ((readByte=is.read()) != -1){

}

 

read(byte[] b)

· 입력 스트림으로부터 매개값으로 주어진 바이트 배열의 길이만큼 바이트를 읽고 배열에 저장

· 실제로 읽은 바이트 수가 배열의 길이보다 작을 경우 읽은 수만큼 리턴

ex) 스트림에서 5개의 바이트가 들어오면, 크기가 3인 바이트 배열(byte[3])로 두 번 만에 읽을 수 있음

https://blog.naver.com/plateauh/222085091595

·  더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메소드는 -1을 리턴하기

   - 이것을 이용해서 읽을 수 있는 마지막 바이트까지 루프를 돌며 읽을 수 있음

 

▶ 예시

InputStream is = new FileInputStream("C;//test.jpg");
int readByte;
byte[] readBytes = new byte[100];

while ((readByte=is.read(readBytes)) != -1){

}

· read() 메소드를 사용하는 것 보다 작업량을 훨씬 줄일 수 있으므로, 많은 양의 바이트를 읽을 때 사용하면 효율적

ex) 입력 스트림에 100개의 바이트가 들어오면 read() 메소드는 100번을 루핑해서 읽어들여야 하지만, read(byte[] b) 메소드는 바이트 배열 길이를 100으로하면 한 번에 읽어 들일 수 있음

 

read(byte[] b, int off, int len)

· 입력 스트림으로부터 len개의 바이트를 읽고, 매개값으로 주어진 바이트 배열 b[off]부터 len개까지 저장

· 메소드 종료 시에 읽은 바이트 수인 len 개를 리턴하고, 실제로 읽은 바이트 수가 len개보다 작을 경우 읽은 수 만큼 리턴

ex) 입력 스트림에서 전체 5개의 바이트가 들어오고, byte[] b의 크기가 10, off의 값이 2, len의 값이 3이라고 가정하자. 입력 스트림에서 들어오는 5개의 바이트 중 3개만 읽어 b[2], b[3], b[4]에 각각 저장된다.

https://blog.naver.com/plateauh/222085091595

· 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면, read() 메소드는 -1을 리턴

 

· read(byte[] b)와 차이점: 한 번에 읽어들이는 바이트 수를 len 매개값으로 조절 가능, 배열에서 저장이 시작되는 인덱스 지정 가능

· off를 0, len을 배열의 길이로 설정하면 read(byte[] b)와 동일

 

▶ 예시

InputStream is = new FileInputStream("C;//test.jpg");
int readByte;
byte[] readBytes = new byte[100];
int readByteNo = is.read(readBytes);

// 위 아래는 동일한 코드다.

InputStream is = new FileInputStream("C;//test.jpg");
int readByte;
byte[] readBytes = new byte[100];
int readByteNo = is.read(readBytes, 0, 100);

 

close()

·  InputStream을 더 이상 사용하지 않을 경우 호출하여 InputStream에서 사용했던 시스템 자원을 풀어줌

 

is.close();

 

OutputStream

·  바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스

·  모든 바이트 기반 출력 스트림 클래스는 이 클래스를 상속받아 만듦

ex) FileOutputStream, PrintStream, BufferedOutputStream, DataOutputStream 클래스

 

OutputStream 클래스에 정의된 메소드

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=javainer&logNo=221479451489

write(int b)메소드

·  매개 변수로 주어진 int 값에서 끝에 있는 1바이트만 출력 스트림으로 보내는 메소드

주의! int 타입이지만, 4바이트 모두를 보내는 것으로 오해하지 말자

https://blog.naver.com/plateauh/222085091595

▶ 예시

       OutputStream os = new FileOutputStream("C:/test.txt");
       byte[] data = "ABC".getBytes();
       for(int i=0; i<data.length; i++){
           os.write(data[i]); // "A", "B", "C"를 하나씩 출력

 

write(byte[] b)메소드

·  매개값으로 주어진 바이트 배열의 모든 바이트를 출력 스트림으로 보내는 메소드

https://blog.naver.com/plateauh/222085091595

 

▶ 예시

OutputStream os = new FileOutputStream("C:/test.txt");
byte[] data = "ABC".getBytes();
os.write(data); // "ABC" 모두 출력

 

write(byte[] b, int off, int len)메소드

 

·  b[off]부터 len개의 바이트를 출력 스트림으로 보내는 메소드

https://blog.naver.com/plateauh/222085091595

 

▶ 예시

OutputStream os = new FileOutputStream("C:/test.txt");
byte[] data = "ABC".getBytes();
os.write(data, 1, 2); // "BC"만 출력

 

flush()와 close() 메소드

· 출력 스트림은 내부에 작은 버퍼(buffer)가 있어서 데이터가 출력되기 전에 버퍼에 쌓여있다가 순서대로 출력

·  flush() 메소드는 버퍼에 잔류하고 있는 데이터를 모두 출력시키고 버퍼를 비우는 역할

   - 프로그램에서 더 이상 출력할 데이터가 없다면 호출하여 버퍼에 잔류하는 모든 데이터가 출력되도록 해야 함

 

· OutputStream을 더 이상 사용하지 않을 경우 close() 메소드를 호출해서 OutputStream에서 사용했던 시스템 자원을 풀어줌

 

▶ 예시

OutputStream os = new FileOutputStream("C:/test.txt");
byte[] data = "ABC".getBytes();
os.write(data);
os.flush();
os.close();

 

Character 스트림

Reader

· 문자 기반 입력 스트림의 최상위 클래스로 추상 클래스

모든 문자 기반 입력 스트림은 이 클래스를 상속받아서 만들어진다. FileReader. BufferedReader, InputStreamReader 클래스 등이  Reader 클래스를 상속하고 있다. 

 

Reader 클래스에 정의된 메소드

read()

· 입력 스트림으로부터 한 개의 문자(2바이트)를 읽고 4바이트 int 타입으로 리턴

· 리턴된 4바이트 중 끝에 있는 2바이트에 문자 데이터가 들어 있음

 

 

· read() 메소드가 리턴한 int 값을 char 타입으로 변환하면 읽은 문자를 얻을 수 있음

 

char charData = (char) read();

 

· 더 이상 입력 스트림으로부터 문자를 읽을 수 없다면 read() -1을 리턴한다.

· 이것을 이용해 읽을 수 있는 마지막 문자까지 루프를 돌며 한 문자씩 읽을 수 있음

 

▶ 예시

Reader reader = new FileReader("C:/test.txt");
int readData;

while((readData=reader.read()) != -1){
   char charData = (char) readData;
}

 

read(char[] cbuf) 메소드

· 입력 스트림으로부터 매개값으로 주어진 문자 배열의 길이만큼 문자를 읽고 배열에 저장

· 읽은 문자 수를 리턴

ex) 입력 스트림에 세 개의 문자가 들어오면, 길이가 2인 문자 배열로 두 번 만에 읽을 수 있음

 

·  read() 메소드와 같이 입력 스트림으로부터 문자를 더 이상 읽을 수 없다면 -1을 리턴

 

▶ 예시

Reader reader = new FileReader("C:/test.txt");
int readData;
char[] cbuf = new char[2];

while((readData=reader.read(cbuf)) != -1){
   char charData = (char) readData;
}

· 많은 양의 문자를 읽을 때 read() 메소드 보다 효율적

 

read(char[] cbuf, int off, int len) 

·  입력 스트림으로부터 len개의 문자만큼 읽고 매개값으로 주어진 문자 배열 cbuf[off]부터 len개까지 저장

· 읽은 문자 수인 len개를 리턴

· 실제로 읽은 문자 수가 len개보다 작을 경우 읽은 수만큼 리턴

·  read(char[] cbuf)  메소드와 같이 문자를 더 이상 읽을 수 없다면 -1을 리턴

· read(char[] cbuf)와 차이점: 한 번에 읽어들이는 문자 수를 len 매개값으로 조절 가능, 배열에서 저장이 시작되는 인덱스를 지정 가능

· off를 0으로, len을 배열의 길이로 준다면 read(char[] cbuf)와 동일

 

▶ 예시

Reader reader = new FileReader("C:/test.txt");
char[] cbuf = new char[100];
int readCharNo = reader.read(cbuf, 0, 100);

 

close() 메소드

· Reader를 더 이상 사용하지 않을 경우 close() 메소드를 호출해서 Reader에서 사용했던 시스템 자원을 풀어줌

 

▶ 예시

reader.close();

 

Writer

· 문자 기반 출력 스트림의 최상위 클래스로 추상 클래스

· 모든 문자 기반 출력 스트림 클래스는 이 클래스를 상속받아 만들어짐

ex) FileWriter, BufferedWriter, PrintWriter, OutputStreamWriter 클래스

Writer 클래스에 존재하는 메서드

write(int c)

·  매개 변수로 주어진 int 값에서 끝에 있는 2바이트 (한 개의 문자)만 출력 스트림으로 보냄

▶ 예시

Writer writer = new FileWriter("C:/test.txt");
char[] data = "홍길동".toCharArray();

for(int i=0; i<data.length; i++){
   writer.write(data[i]); //'홍','길','동'을 하나씩 출력
}

 

write(char[] cbuf)

·  매개값으로 주어진 char[] 배열의 모든 문자를 출력 스트림으로 보냄

 

▶ 예시

Writer writer = new FileWriter("C:/test.txt");
char[] data = "홍길동".toCharArray();
writer.write(data); //"홍길동"을 모두 출력

 

write(char[] c, int off, int len)

·  c[off]부터 len개의 문자를 출력스트림으로 보냄

 

▶ 예시

Writer writer = new FileWriter("C:/test.txt");
char[] data = "홍길동".toCharArray();
writer.write(data,1,2); //"길동"만 출력

 

write(String str)와 write(String str, int off, int len)

· 문자열을 좀 더 쉽게 보내기 위해서 Writer에서 제공하는 메서드

· write(String r): 문자열 전체를 출력 스트림으로 보냄

· write(String str, int off, int len): 주어진 문자열을 off 순번부터 len개까지의 문자를 보냄

 

▶ 예시

Writer writer = new FileWriter("C:/test.txt");
String data = "hello java";
writer.write(data);
writer.flush();
writer.close();

 

·  문자 출력 스트림은 내부에 작은 버퍼가 있어 데이터가 출력되기 전에 버퍼에 쌓여있다가 순서대로 출력

 

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

· 자바에서는 스크린과 키보드를 통한 입출력 방법인 표준 입출력을 제공

· 콘솔: 시스템을 사용하기 위해 키보드로 입력 받고, 화면으로 출력하는 소프트웨어 

 

System.in

· System 클래스의 in 정적 필드: 프로그램이 콘솔로부터 데이터를 입력 받는 기능을 제공

· Sytem.in은 InputStream 타입

 

InputStream is = System.in;

 

· 키보드로부터 어떤 키가 입력되었는지 확인하려면 InputStream의 read() 메소드로 한 바이트를 읽기

· 리턴된 int 값에는 십진수 아스키 코드가 들어 있음

 

int asciiCode = is.read();

 

· 아스키코드: 1byte로 표현되는 256가지의 숫자에 알파벳, 아라비아 숫자, 특수 기호를 매칭

아스키코드 자세한 설명

 

· 아스키 코드로 얻을 결과가 어떤 문자인지 알고 싶다면 아스키 코드를 char로 타입 변환하기

char inputChar = (char) is.read();

 

▶ 예시 - ‘a’,’b’,’c’,’d’,’e’를 차례대로 입력하고, 엔터를 누르기

import java.io.*;

public class InputStreamExam {

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

       InputStream is = System.in;

      for(int i=0; i<5;i++){
          char inputChar = (char)is.read();
          System.out.printf("%c \n",inputChar);
      }
   }
}

 

결과

 

· 문제점: InputStream의 read() 메소드는 1바이트만 읽기 때문에 1바이트의 아스키 코드로 표현되는 숫자, 영어, 특수문자는 프로그램에서 잘 읽을 수 있지만, 한글과 같이 2바이트로 필요로 하는 유니코드는 다른 방법을 사용해야함

 

· 해결책: read(byte[] b), read(byte[] b, int off, len) 메소드로 입력된 내용을 바이트 배열로 받고, 이를 이용해 String 객체를 생성

 

·  영문자 15자 또는 한글 7자를 저장하려면 다음과 같이 바이트 배열을 선언

byte[] byteData = new byte[15];
int readByteNo = System.in.read(byteData;) // 읽은 바이트 수 저장

 

· 바이트 배열에 저장된 아스키 코드를 사용하려면 문자열로 변환해야함

· 변환할 문자열은 바이트 배열의 0번 인덱스에서 시작해서 읽은 바이트 수 -2만큼

   - 2를 빼는 이유: Enter키에 해당하는 마지막 두 바이트를 제외하기 위해서

· 바이트 배열을 문자열로 변환할 때는 String 생성자를 이용

String strData = new String(byteData, 0, readByteNo-2); // 바이트배열, 시작인덱스, 읽은 바이트 수 -2

 

▶ 예시

import java.io.*;



public class InputStreamExam {

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

       InputStream is = System.in;
       byte[] datas = new byte[100];

       System.out.print("이름: ");
       
       int nameByte = is.read(datas);
       String name = new String(datas, 0, nameByte-2);

       System.out.print("직업: ");
       int jobByte = is.read(datas);
       String job = new String(datas, 0, jobByte-2);
       
       System.out.println("입력한 이름: "+name);
       System.out.println("입력한 직업: "+job);
   }
}

 

결과

 

System.out

· System 클래스의 out 정적 필드: 콘솔로 데이터를 출력하기 위한 기능 제공

· out 필드는 PrintStream 타입의 필드이며, PrintStream은 OutputStream의 하위 클래스 x

 

OutputStream os = System.out;

 

· 콘솔로 1개의 바이트를 출력하려면 OutputStream의 write(int b) 메소드를 이용

· 이때 바이트 값은 아스키 코드, write() 메소드는 아스키 코드를 문자로 콘솔에 출력

 

▶ 예시

import java.io.IOException;
import java.io.OutputStream;


public class SystemExam {

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

       OutputStream os = System.out;
       byte b = 97;
       os.write(b);
       os.flush();
       os.close();
   }
}

결과

 

·  한글(2바이트)을 출력하는 방법: 한글을 바이트 배열로 얻은 후 write(byte[] b) 또는 write(byte[] b, int off, int len) 메소드로 콘솔에 출력

 

▶ 예시

import java.io.IOException;
import java.io.OutputStream;

public class SystemExam {

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

       OutputStream os = System.out;
       String name = "홍길동";
       byte[] nameBytes = name.getBytes();

       os.write(nameBytes);
       
       os.flush();
       os.close();
   }
}

결과

 

System.err

·  에러를 출력위한 스트림

·  System.out 처럼 콘솔로 데이터를 출력하기 위한 스트림이지만, 버퍼링 지원 x

   - 버퍼링 중 프로그램이 멈추면 버퍼링된 내용은 출력되지 않기 때문에, err을 보다 정확하고 빠르게 출력하기 위한 조치

 

▶ 예시

import java.io.IOException;
import java.io.OutputStream;

public class SystemExam {

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

       OutputStream os = System.err;

       String name = "홍길동";
       byte[] nameBytes = name.getBytes();

       os.write(nameBytes);

       os.flush();
       os.close();
   }
}

결과

 

파일 읽고 쓰기

 

File 클래스

 

· 파일 크기, 파일 속성, 파일 이름 등의 정보를 얻어내는 기능과 파일 생성 및 삭제 기능을 제공

· 디렉토리 생성 및 디렉토리에 존재하는 파일 리스트를 얻는 것도 가능

· java.io에서 제공

 

▶ 예시 - C:\Temp 디렉토리의 file.txt 파일을 File 객체로 생성

File file = new File(“C:\\Temp\\file.txt”);
File file = new File(“C:/Temp/file.txt”);

· File.separator 상수를 출력하면 해당 운영체제에서 사용하는 디렉토리 구분자 확인 가능

   - 디렉토리 구분자는 운영체제 마다 다르며 윈도우는 \ 또는 /, 리눅스는 /를 사용

 

· exists() 메서드: 경로에 실제로 파일이나 디렉토리가 있는지 확인

 

boolean isExist = file.exists();

 

파일 또는 디렉토리를 생성,삭제하는 메소드

리턴 타입 메소드 실행
boolean createNewFile() 새로운 파일 생성
boolean mkdir() 새로운 디렉토리 생성
boolean mkdirs() 경로상에 없는 모든 디렉토리 생성
boolean delete() 파일 또는 디렉토리 삭제

 

존재하는 파일, 디렉토리의 정보를 얻는 메소드

리턴 타 메소드 실행
boolean canExecute() 실행할 수 있는 파일인지 여부
boolean canRead() 읽을 수 있는 파일인지 여부
boolean canWrite() 수정 및 저장할 수 있는 파일인지 여부
String getName() 파일의 이름을 리턴
String getParent() 부모 디렉토리를 리턴
File getParentFile() 부모 디렉토리를 File 객체로 생성 후 리턴
String getPath() 전체 경로를 리턴
boolean isDirectory() 디렉토리인지 여부
boolean isFile() 파일인지 여부
boolean isHidden() 숨김 파일인지 여부
long lastModified() 마지막 수정 날짜 및 시간을 리턴
long length() 파일의 크기를 리턴
String[] list() 디렉토리에 포함된 파일 및 서브디렉토리의 목록 전부를 String 배열로 리턴
String[] list(FilenameFilter filter) 디렉토리에 포함된 파일 및 서브디렉토리 목록 중에 FilenameFilter에 맞는 것만 String 배열로 리턴
File[] listFiles() 디렉토리에 포함된 파일 및 서브 디렉토리 목록 전부를 File 배열로 리턴
File[] listFiles(FilenameFilter filter) 디렉토리에 포함된 파일 및 서브디렉토리 목록 중에 FilenameFilter에 맞는 것만 File 배열로 리턴

 

· 파일의 데이터를 읽고 쓰는 기능은 제공하지 않아, 이를 위해 스트림을 사용

 

FileInputStream

·  파일을 바이트 단위로 읽어들일 때 사용하는 바이트 기반 입력 스트림

·  바이트 단위로 읽기 때문에 그림, 오디오, 비디오, 텍스트 파일 등 모든 종류의 파일을 읽을 수 있음

 

▶ 예시

//첫번째 방법
FileInputStream fis = new FileInputStream(“C:/Temp/image.gif”);

//두번째 방법
File file = new File(“C:/Temp/image.gif”);
FileInputStream fis = new FileInputStream(file);

 

· 위 방법은 파일이 존재하지 않으면 FileNotFountException을 발생시키므로 try-catch문으로 예외 처리 필수

· FileInputStream은 InputStream의 하위 클래스이기 때문에 InputStream과 사용 방법이 동일하므로 read() 등의 메소드를 사용할 수 있음

 

▶ 예시

import java.io.FileInputStream;

public class FileInputStreamExam {

   public static void main(String[] args) {

       try{
           FileInputStream fis = new FileInputStream("/Users/simseungcheol/Desktop/studyProject/whiteshipjavastudy/src/main/java/week14/FileInputStreamExam.java");
           int data;

           while((data = fis.read()) != -1){
               System.out.write(data);
           }

           fis.close();
       }catch (Exception e){
           e.printStackTrace();
       }
   }
}

 

FileOutputStream

· 바이트 단위로 데이터를 파일에 저장할 때 사용하는 바이트 기반 출력 스트림

· 바이트 단위로 저장하기 때문에 그림, 오디오, 비디오, 텍스트 등 모든 종류의 데이터를 파일로 저장 가능

 

▶ 예시

//방법1
FileOutputStream fis = new FileOutputStream(“C:/Temp/image.gif”);

 //방법 2
File file = new File(“C:/Temp/image.gif”);
FileOutputStream fis = new FileOutputStream(file);

 

· 파일이 이미 존재할 경우, 데이터를 출력하면 파일을 덮어쓰게 되므로, 기존의 파일 내용은 사라짐

· 기존의 파일 내용 끝에 데이터를 추가할 경우 FileOutputStream 생성자의 두 번째 매개값을 true로 설정

 

File file = new File(“C:/Temp/data.txt”, true);
FileOutputStream fis = new FileOutputStream(file, true);

 

·  FileOutputStream은 OutputStream의 하위 클래스이기 때문에 OutputStream과 사용 방법이 동일하므로 write() 등의 메소드 사용 가능

 

▶ 예시 - 원본 파일을 타겟 파일로 복사

 

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;


public class FileInputStreamExam {

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

           String originalFileName = "/Users/simseungcheol/Desktop/studyProject/whiteshipjavastudy/src/main/java/week14/image.png";
           String targetFileName = "/Users/simseungcheol/Desktop/studyProject/whiteshipjavastudy/src/main/java/week14/copy.png";

           FileInputStream fis = new FileInputStream(originalFileName);
           FileOutputStream fos = new FileOutputStream(targetFileName);

           int readByteNo;

           byte[] readBytes = new byte[100];
           
           while((readByteNo = fis.read(readBytes)) != -1){
               fos.write(readBytes, 0, readByteNo);
           }

 
           fos.flush();
           fos.close();
           fis.close();

       System.out.println("복사 완료");
   }
}

결과 - 새로운 파일 생성

 

· 이외에도 텍스트 파일을 문자 기반으로 입출력하는 FileReader, FileWriter 클래스가 존재

 

버퍼 (Buffer) / 채널 (Channel) 기반의 I/O

·  버퍼와 채널 기반의 I/O: 기존의 자바 IO가 개선된 NIO 방식의 입출력

· 자바 4부터 새로운 입출력(New Input/Oput) java.nio 패키지가 추가

· 자바 7에서는 자바 IO와 NIO 사이에 일관성 없는 클래스 설계를 바로 잡고, 비동기 채널 등의 네트워크 지크 지원을 강화한 NIO.2 API가 추가

 

·  NIO는 채널기반으로 스트림과 달리 양방향 입출력이 가능

ex) IO는 하나의 파일에 데이터 입출력을 위해 FileInputStream과 FileOutputStream이 별도로 필요하다. 하지만 NIO는  입출력을 위한 별도의 채널을 만들 필요가 없다. 하나의 파일에서 데이터를 읽고 저장하는 작업을 모두 해야 한다면 FileChannel 하나만 생성하면 된다.

 

·  NIO 방식은 버퍼(Buffer: 메모리 저장소)를 사용하여 복수 개의  바이트를 한꺼번에 입출력

 

이러한 방식은 출력 스트림이 1바이트를 쓰면 입력 스트림이 1바이트를 읽는 IO보다 빠르다. 그래서 IO는 버퍼를 제공해주는 보조 스트림인 BufferedInputStream, BufferedOutputStream을 연결해서 사용하기도 한다.

 

다음 예제는 java.nio 패키지를 통한 파일의 입출력을 보여준다.

 

▶ 예시

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class FileChannelExam {

   public static void main(String[] args) throws IOException {
   
       Path path = Paths.get("/Users/simseungcheol/Desktop/studyProject/whiteshipjavastudy/src/main/java/week14/file.txt");

       //파일 쓰기
       FileChannel fileChannel = FileChannel.open(path,
               StandardOpenOption.WRITE,
               StandardOpenOption.CREATE,
               StandardOpenOption.READ);

       String writeData = "안녕하세요";
       Charset charset = Charset.defaultCharset();
       ByteBuffer writeByteBuffer = charset.encode(writeData);
       int writeByteCount = fileChannel.write(writeByteBuffer);
       
       System.out.println(writeByteCount+"바이트의 file.txt 파일을 생성했습니다.");

       //파일 읽기
       fileChannel = FileChannel.open(path,
               StandardOpenOption.READ);

       ByteBuffer readByteBuffer = ByteBuffer.allocate(100);
       String readData = "";
       int readByteCount;

       while(true){
           readByteCount = fileChannel.read(readByteBuffer);
           if(readByteCount == -1) break;
           readByteBuffer.flip();
           readData += charset.decode(readByteBuffer).toString();
           readByteBuffer.clear();
       }

       System.out.println("file.txt 파일을 읽었습니다.\n내용:" + readData);

       fileChannel.close();
   }
}

 

출처

이것이 자바다

https://hyeonstorage.tistory.com/235

 

반응형

'자바' 카테고리의 다른 글

[Java] NIO2란?  (0) 2021.09.24
[Java] 자바의 Serializable  (0) 2021.09.14
[Java] 자바의 Scanner 클래스 사용하기  (0) 2021.09.10
[Java] 자바 7의 새로운 기능  (0) 2021.09.10
[Java] 자바의 스트림(Stream)  (0) 2021.09.09

댓글