[JAVA] 입출력(I/O)

입출력(I/O)

- I/O란 Input과 Output의 약자로 입력과 출력, 간단히 줄여서 입출력이라고 한다. 입출력은 컴퓨터 내부 또는 외부의 장치와 프로그램간의 데이터를 주고받는 것을 말한다.

- 입력의 근원지에서 InputStream을 거쳐 JVM에 데이터가 들어가고, JVM에서 Output Stream을 통해 출력의 목적지로 데이터를 내보낸다.

└ 입력의 근원지 : 시스템(키보드의 입력), 파일, 네트워크(net, socket)

└ 출력의 목적지 : 시스템(모니터). 파일(HDD), 네트워크

 

 

 

스트림(stream)

- 데이터를 전달할 두 대상을 연결하고 데이터를 전송할 수 있는 무언가가 필요한데 이것을 스트림이라고 한다. 즉, 스트림은 데이터를 운반하는데 사용되는 연결통로이다.

- 스트림은 단방향통신만 가능하기 때문에 하나의 스트림으로 입력과 출력을 동시에 처리할 수 없다. 따라서 입력과 출력을 위한 입력스트림(input stream)과 출력스트림(output stream)이 필요하다.

- 스트림은 먼저 보낸 데이터를 먼저 받게 되어있다. 큐와 같은 FIFO구조로 되어 있다.

- java.io package에서 stream을 제공한다.

- 크게 바이트기반 스트림과 문자기반 스트림으로 나뉜다.

 

 

 

바이트기반 스트림(InputStream, OutputStream), 8bit Stream

 

읽기(InputStream)

└DataInputStream

└FileInputStream

└ObjectInputStream

...

 

쓰기(OutputStream)

└FileOutputStream

└ObjectOutputStream

...

- 바이트단위로 데이터를 전송한다. 입출력의 단위가 1byte라는 뜻이다.

- 모든 데이터의 읽기와 쓰기가 가능하다.

- 속도가 빠르지만 한번에 움직이는 데이터의 양이 적다.

 

 

 

문자열 기반 스트림(Reader, Writer), 16bit Stream

 

읽기(Reader)

└FileReader

└BufferedReader

└InputStreamReader(8bit와 16bit연결)

...

쓰기(Writer)

└FileWriter

└BufferedWriter

...

- C언어와 달리 Java에서는 한문자를 의미하는 char형이 1byte가 아니라 2byte이기 때문에 바이트기반의 스트림으로 2byte인 문자를 처리하는 데는 어려움이 있다. 이 점을 보완하기 위해서 문자기반의 스트림이 제공된다. 문자데이터를 입출력할 때는 바이트기반 스트림 대신 문자기반 스트림을 사용해야한다.

- 속도는 느리지만 한번에 움직이는 데이터의 양이 많다.

더보기

FileInputStream

- FileInputStream(File file)

Creates a FileInputStream by opening a connection to an actual file, the file named by the File object file in the file system.

- FileInputStream(FileDescriptor fdObj)

Creates a FileInputStream by using the file descriptor fdObj, which represents an existing connection to an actual file in the file system.

- FileInputStream(String name)

Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system.

- int read()

Reads a byte of data from this input stream.

데이터의 코드값이 리턴된다.(코드값 확인하기 : 이클립스 - alt를 누른 상태에서+코드값을 적은 후 손을 때면 문자가 적혀진다.)

한글은 유니코드이므로 이 값을 확인할 수 없다. 또한 위 read()는 1byte씩 읽어오는데 한글은 2byte이므로 강제로 잘려져 들어오게 된다.

 

 

 

[참고] "를 문자열로 나타내기 위해서는 \특수문자 형식으로 써주어야 한다. (ex. \n, \r(return : 커서를 가장 앞으로), \t, \b(backspace), \', \", \\, \f(printer new line))

-------------------------------------------------------------------

// '\'뒤에는 정의된 예약어가 들어와야하므로 에러

//System.out.println("c:\dev\test.txt");

// 따라서 '\'를 표현하기 위해서는 '\\'라고 명시해주어야 한다.

System.out.println("c:\\dev\\test.txt");  // \ window의 경로으 경로 표기 방법

 

System.out.println("c:/dev/test.txt");  // / unix의 경로 표기 방법

-------------------------------------------------------------------

파일의 경로를 문자열로 넣을 경우 가장 큰 문제점은 파일의 정보를 알 수가 없다. 따라서 FileNotFoundException의 예외에 대해 처리해주어야 한다. 이보다 좋은 방법은 File클래스를 이용하는 것이다. File클래스를 이용하면 파일에 대한 정보를 얻을 수 있다.

 

 

 

File

- File(File parent, String child)

Creates a new File instance from a parent abstract pathname and a child pathname string.

- File(String pathname)

Creates a new File instance by converting the given pathname string into an abstract pathname.

- File(String parent, String child)

Creates a new File instance from a parent pathname string and a child pathname string.

- File(URI uri)

Creates a new File instance by converting the given file: URI into an abstract pathname.

 

 

 

BufferedReader

- BufferedReader(Reader in)

Creates a buffering character-input stream that uses a default-sized input buffer.

- BufferedReader(Reader in, int sz)

Creates a buffering character-input stream that uses an input buffer of the specified size.

- String readLine()

Reads a line of text.

- 문자열을 리턴한다. 읽은 내용이 없을 경우 null을 리턴한다.

 

 

 

InputStreamReader

- InputStreamReader(InputStream in)

Creates an InputStreamReader that uses the default charset.

- InputStreamReader(InputStream in, Charset cs)

Creates an InputStreamReader that uses the given charset.

- InputStreamReader(InputStream in, CharsetDecoder dec)

Creates an InputStreamReader that uses the given charset decoder.

- InputStreamReader(InputStream in, String charsetName)

Creates an InputStreamReader that uses the named charset.

- 8bit와 16bit를 연결해주고 charset를 변경해준다.

 

 

 

 

 

 

바이트기반 스트림과 문자열 기반 스트림을 이용하여 *.txt파일 읽어들이기

- java_read.txt파일을 읽어들이는 예제이다.

- 파일의 데이터는 바이트기반의 FileInputStream을 통해 읽어들이고 파일이 한글로 작성되었으므로 JVM은 문자열기반의 BufferedReader로 받는다. 이때 두 스트림의 비트가 달라 연결되지 않으므로 중간자 역할로 InputStreamReader로 중계해준다.

------------------------------------------------

FileInputStream fis = new FileInputStream(file);

InputStreamReader isr = new InputStreamReader(fis);

 

BufferedReader br = new BufferedReader(isr);

[참고] 메서드 참고 참고하길

------------------------------------------------

 

 

 

--------------------------------------------------------------------------------------------------
Reader를 이용하여 *.txt파일 읽어들이기 예제
 

public class TestFileRead {

public static void main(String[] args) {

// 해당 경로에 파일이 있는지 판단하고 파일의 정보를 얻기 위해서 File Class를 사용한다.

File file = new File("C:/.../java_read.txt");

if(file.exists()){  // 파일의 존재 유무 확인

// 존재하면 파일 읽기 시작

try {

//1. 파일에 스트림 연결

BufferedReader br = new BufferedReader(new FileReader(file));  // fileReader() throws FileNotFoundException

 

//2. 파일의 내용 읽기

//2-1. 한줄씩 읽기

/*

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine());

System.out.println(br.readLine()); // 더이상 참조하는 주소가 없으면 null을 반환

*/

 

//2-2. 한글자 읽기

//System.out.println((char)br.read());

/*

* 주의!

* 16bit스트림이므로 한글이 잘 나오지만 8bit스트림일 경우 나오지 않는다.

* 파일과 프로그램의 인코딩셋이 맞지 않으면 깨진다.

*/

 

//2-3. 반복문을 이용하여 한줄씩 읽기

String line = "";  // 파일로부터 읽어온 줄을 저장하기 위한 변수

while((line = br.readLine()) != null){  // 읽어온 값이 null이 아니라면 반복한다. 즉, 파일의 끝이 아니라면

System.out.println(line.replace("이진기", "우주미남").replace("진기", "춤신춤왕"));  

//replace(oldChar, newChar)을 이용하여 읽어들인 정보를 가송할 수도 있다.

/*

* 유용!

* 메서드 체인을 이용하여 한글자씩 띄어진 글자도 처리할 수 있다.

* 이런 점을 이용하여 비속어 처리를 할 수 있다.

* ex) 개놈 or 개 놈 ----(비속어처리)----> ☆ ★

* replace("개놈","☆★") or replace("개","☆").replace("놈","★")

*/

}

 

//3. 연결 끊기

br.close();  // close() throws IOException

} catch (FileNotFoundException e) {

/*

* 예외처리 팁!

* 1.7버전에 추가된 문법 catch (xxxxxxException | xxxxxxException 변수명)

* '|'를 사용하여 여러 exception을 묶어줄 수 있다.

* 상속의 관계가 있는 예외들을 묶으면 에러!(부모로 모두 받을 수 있으므로)

* 여기서는 IOException -> FileNotFoundException의 관계를 가진다.

*/

System.err.println("입력하신 경로에 파일이 존재하지 않습니다.");

e.printStackTrace();

} catch (IOException e) {

System.err.println("스트림에 문제 발생");

e.printStackTrace();

}

 

}

else

System.out.println("파일 없음. 경로를 확인해주세요.");

}

 

}

--------------------------------------------------------------------------------------------------