새소식

java

입출력

  • -

 

1. 콘솔 입출력

자바 코드에서 사용자가 입력한 문자열을 얻기 위해서는 자바의 System.in 을 사용한다.

(read()메서드는 입력스트림으로 부터 한개의 문자를 읽고 리턴)

import java.io.IOException; import java.io.InputStream; public class Sample { public static void main(String[] args) throws IOException { // InputStream으로 부터 값을 읽어들일 때는 IOException이 발생할 수 있기 때문에 예외처리를 해야 하는데 throws로 그 예외처리를 뒤로 미루게 한 것 InputStream in = System.in; int a; a = in.read(); // InputStream의 read메서드는 1 byte의 사용자의 입력을 받아들인다. // 하지만 read 메서드로 읽은 1 byte의 데이터는 byte 자료형으로 저장되는 것이 아니라 int 자료형으로 저장된다. // 저장되는 int 값은 0-255 사이의 정수값으로 아스키 코드값 (0 이라는 숫자에 해당되는 아스키코드값은 48, a 라는 문자에 해당되는 아스키코드값은 97) System.out.println(a); } } // InputStream은 자바의 내장 클래스 // 자바의 내장 클래스중에 java.lang 패키지에 속해 있지 않은 클래스는 위 코드처럼 필요할 때 항상 import 해서 사용 // System.in은 InputStream의 객체 // 프로그램을 실행시켜보면 프로그램은 종료되지 않고 사용자의 입력을 대기하고 있음 => InputStream의 read()메서드가 호출되어 사용자의 입력을 받을 때까지 프로그램이 대기하기 때문 // a를 입력하면 a에 해당하는 아스키 코드값인 97이 출력됨

 

a를 입력해도 97이 출력될 것이고 abc를 입력해도 97이 출력될 것이다.

>>

InputStream의 read 메서드는 1 byte만 읽기 때문

(사용자는 "abc"라는 총 3 byte의 데이터를 전달했지만 프로그램에서 1 byte만 읽은 경우)

 

이렇게 사용자가 전달한 1 byte의 데이터 또는 3 byte의 데이터를 다른 말로 입력 스트림(Stream)이라고 한다

스트림이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름이다.

자바에서는 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림(stream)이라는 흐름을 통해 다룬다.

스트림과 관련하여 프로그래밍에서는 아래의 리스트들을 스트림이라 할 수 있다.

1. 파일 데이터 (파일은 그 시작과 끝이 있는 데이터의 스트림이다.)

2. HTTP 송수신 데이터 (브라우저가 요청하고 서버가 응답하는 HTTP 형태의 데이터도 스트림이다.)

3. 키보드 입력 (사용자가 키보드로 입력하는 문자열은 스트림이다.)

 

자바에서는 java.io 패키지를 통해 InputStream과 OutputStream 클래스를 별도로 제공하고

자바에서의 스트림 생성이란 이러한 스트림 클래스 타입의 인스턴스를 생성한다는 의미이다.

(InputStream 클래스에는 read() 메소드가, OutputStream 클래스에는 write() 메소드가 각각 추상 메소드로 포함)

 

 

byte 대신 문자로 입력 스트림을 읽으려면 InputStreamReader를 사용

( InputStreamReader 객체를 생성할 때는 다음과 같이 생성자의 입력으로 InputStream 객체가 필요)

import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class Sample { public static void main(String[] args) throws IOException { InputStream in = System.in; InputStreamReader reader = new InputStreamReader(in); // InputStreamReader 객체를 생성할 때는 다음과 같이 생성자의 입력으로 InputStream 객체(예시에선 in)가 필요 char[] a = new char[3]; // InputStreamReader를 이용하면 다음처럼 byte 대신 char 배열을 사용할 수 있다. reader.read(a); // 배열을 만든 후 read 메서드의 입력값으로 전달하면 콘솔 입력이 해당 배열에 저장이 된다. System.out.println(a); } }

프로그램을 실행하고 "abc" 입력 후 엔터키로 사용자 입력을 전달하면 "abc"라는 문자열이 한꺼번에 출력된다.

 

 

사용자가 엔터키를 입력할 때까지 사용자의 입력을 전부 받아들이고 싶으면 BufferedReader를 이용한다.

(BufferedReader는 객체 생성시 생성자의 입력값으로 InputStreamReader의 객체가 필요!!!!)

import java.io.IOException; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class Sample { public static void main(String[] args) throws IOException { InputStream in = System.in; InputStreamReader reader = new InputStreamReader(in); BufferedReader br = new BufferedReader(reader); // BufferedReader는 객체 생성시 생성자의 입력값으로 InputStreamReader의 객체가 필요!!!! String a = br.readLine(); // BufferedReader의 readLine메서드를 이용하면 사용자가 엔터키를 입력할 때까지 입력했던 문자열 전부를 읽을 수 있게 된다. System.out.println(a); } }

입력을 받는 InputStreamReader()를 통한 객체를 이용해서

BufferedReader의 객체를 생성하는데, 해당 객체 각 입력을 버퍼에 저장하여 String에 저장할 수 있게 함

 

BufferedReader의 readline()메서드는 텍스트 파일을 한 줄씩 읽어서 리턴하고, 없으면 null을 리턴한다

 

InputStream은 byte를 읽고, InputStreamReader는 char를 읽고, BufferedReader는 String을 읽는다.

 

+@

<Scanner>

기본적이 데이터타입들을 입력받을 수 있고, 공백(\r)/개행(\n) 기준으로 읽는다.

import java.util.Scanner; // java.util.Scanner 클래스를 import public class Sample { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // Scanner 클래스는 생성자의 입력으로 System.in, 즉 콘솔입력인 InputStream을 필요로 한다. System.out.println(sc.next()); // Scanner 객체의 next() 메서드는 단어 하나(Token)를 읽어들인다. // Scanner 클래스에는 단어 뿐만 아니라 숫자, 문자열등 다양하게 읽어 들일 수 있는 여러 메서드들이 있다. // ex: next - 단어 nextLine - 라인 nextInt - 정수 } }

버퍼 사이즈가 1024 char이기 때문에

많은 입력을 필요로 할 경우에는 성능상 좋지 못한 결과를 불러온다.

(버퍼 사이즈도 Scanner가 1024 char인데 비해,

BufferedReader는 8192 char(16,384byte) 이기 때문에 입력이 많을 때 BufferedReader가 유리)

BufferedReader는 동기화 되기 때문에 멀티 쓰레드 환경에서 안전하고,

Scanner는 동기화가 되지 않기 때문에 멀티 쓰레드 환경에서 안전하지 않다.

 

+@2

콘솔 출력과 관련하여 System.out.println 메서드를 사용해 왔는데, System.out은 PrintStream 클래스의 객체이다.

(PrintStream은 콘솔에 값을 출력할 때 사용되는 클래스이다.)

System.out.println은 콘솔에 문자열을 출력할 경우나 디버깅 시 많이 사용한다.

 

+@3

next()는 공백/개행 전까지 읽고 nextline()은 공백과 상관없이 개행이 나올때까지 읽는데

next()는 개행이 버퍼에 남지만, nextline()은 개행도 버퍼에서 가져온다.

 

 

2. 파일 입출력

<파일 쓰기>

import java.io.FileOutputStream; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { FileOutputStream output = new FileOutputStream("c:/out.txt"); output.close(); // 사용한 파일 객체를 닫아준다. (생략 가능, 자바 프로그램이 종료할 때 사용한 파일 객체를 자동으로 닫아주기 때문) } } // 사용했던 파일을 닫지 않고 다시 사용하려고 할 경우에는 오류가 발생하기에 직접 사용한 파일을 닫아주는 것이 좋다.

위 예제를 실행해 보면 c:/ 디렉토리 바로 밑에 새로운 파일(out.txt)이 하나 생성된다.

(맥(Mac)이나 유닉스 환경에서 실행할 경우 c:/ 디렉터리가 없으므로 디렉터리명을 적절하게 변경하여 실행해야된다.)

 

파일을 생성하기 위해 FileOutputStream 클래스를 사용하였는데,

FileOutputStream 객체를 생성하기 위해서는 생성자의 입력으로 파일명을 넘겨주어야 한다.

(예제는 경로를 포함하여 c:/out.txt라는 파일명을 생성자의 입력으로 전달)

 

import java.io.FileOutputStream; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { FileOutputStream output = new FileOutputStream("c:/out.txt"); for(int i=1; i<11; i++) { String data = i+" 번째 줄입니다.\r\n"; output.write(data.getBytes()); // FileOutputStream에 값을 쓸 때는 byte배열로 써야 하므로 위와같이 String을 byte배열로 바꾸어 주는 getBytes() 메서드를 이용 } output.close(); } }

InputStream과 마찬가지로 OutputStream 역시 바이트 단위로 데이터를 처리하는 클래스

(ileOutputStream은 OutputStream클래스를 상속받아 만든 클래스인데 바이트 단위로 데이터를 처리하게끔 되어 있다.)

 

 

문자열을 파일에 쓸 때에는 String을 byte배열로 변환해야 하기 때문에 FileOutputStream이 좀 불편하다. 

import java.io.FileWriter; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("c:/out.txt"); for(int i=1; i<11; i++) { String data = i+" 번째 줄입니다.\r\n"; fw.write(data); } fw.close(); } } // 콘솔대신에 파일로 출력하는 방법

 

 

for(int i=1; i<11; i++) { String data = i+" 번째 줄입니다."; System.out.println(data); } // 지금까지 계속 사용해 왔던 콘솔 출력 방법

FileOutputStream 대신에 FileWriter를 이용하면 byte 배열 대신 문자열(String)을 사용할수 있어 편리하다.

하지만, FileWriter를 사용하더라도 \r\n을 문자열 뒤에 덧 붙여야 하는 불편함은 여전히 남아있다.

이런 불편함을 해소하려면 FileWriter대신 PrintWriter를 사용

PrintWriter를 이용하면 \r\n을 덧붙이는 대신 println이라는 메서드를 사용할 수 있다.

PrintWriter의 println()메서드는 내용을 콘솔로 출력하는 것이 아니라, 파일로 출력한다.

 

문자열을 파일에 출력한다는 말은 Text 를 Text 파일에 저장한다는 말과도 같다.

 

<파일에 내용 추가>

파일에 내용을 쓰고 난 후에 또 새로운 내용을 추가하고 싶을 때 아래의 예제 참고

import java.io.FileWriter; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("c:/out.txt"); for(int i=1; i<11; i++) { String data = i+" 번째 줄입니다.\r\n"; fw.write(data); } fw.close(); FileWriter fw2 = new FileWriter("c:/out.txt", true); // 파일을 추가 모드로 연다. for(int i=11; i<21; i++) { String data = i+" 번째 줄입니다.\r\n"; fw2.write(data); } fw2.close(); } }

fw2 객체는 FileWriter("c:/out.txt", true) 와 같이 두번째 파라미터를 추가로 전달하여 생성

두번째 boolean 입력 파라미터(예제의 값은 true)는 파일을 추가모드(append)로 열것인지에 대한 구분값

파일을 추가모드로 열면 기존파일의 내용을 덮어쓰지 않고 이후부터 파일이 쓰여진다

 

FileWriter대신 PrintWriter를 이용하고 싶은 경우에는 다음과 같이 변경

import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class Sample { public static void main(String[] args) throws IOException { PrintWriter pw = new PrintWriter("c:/out.txt"); for(int i=1; i<11; i++) { String data = i+" 번째 줄입니다."; pw.println(data); } pw.close(); PrintWriter pw2 = new PrintWriter(new FileWriter("c:/out.txt", true)); for(int i=11; i<21; i++) { String data = i+" 번째 줄입니다."; pw2.println(data); } pw2.close(); } }

PrintWriter를 사용할 경우에는 생성자의 파라미터로 파일명 대신 추가모드로 열린 FileWriter의 객체를 전달

 

 

import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("file_writer.txt"); fw.write("Hello this is file writer"); fw.close(); // FileWriter 그대로 쓰는 방식 // new FileWriter도 파일을 생성합니다. 기존 파일이 있다면 덮어쓰기(Override) 합니다. // close 메소드를 사용하지 않으면 파일작성이 완료되지 않습니다. BufferedWriter bw = new BufferedWriter( new FileWriter("D:\\Programming\\JavaPRJ\\smoothiejava\\b.txt")); bw.write("Hello\n"); bw.write("using Buffered Writer"); bw.write("777"); bw.close(); // BufferedWriter 로 출력내용을 버퍼에 받아서 쓰는 방식 // BufferedWriter는 출력기(Writer)로써 받는 매개변수 객체 종류에 따라 콘솔에 출력할 수도 있습니다. } }

 

<파일 읽기>

import java.io.FileInputStream; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { byte[] b = new byte[1024]; FileInputStream input = new FileInputStream("c:/out.txt"); input.read(b); System.out.println(new String(b)); // byte 배열을 문자열로 변경하여 출력 // 바이트 배열을 문자열로 변경할 때는 new String(바이트배열) 처럼 사용하여 변경 input.close(); } }

파일을 읽기 위해서는 위 예처럼 FileInputStream 클래스를 이용

(byte 배열을 이용하여 파일을 읽어야 하기 때문에 읽어야 하는 정확한 길이를 모를 경우에는 좀 불편한 방법)

 

파일을 라인 단위로 읽을 때

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class Sample { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("c:/out.txt")); while(true) { String line = br.readLine(); if (line==null) break; // 더 이상 읽을 라인이 없을 경우 while 문을 빠져나간다. System.out.println(line); } br.close(); } }

FileInputStream 대신 FileReader와 BufferedReader의 조합을 사용하면 라인단위로 파일을 읽을 수 있다.

BufferedReader의 readLine 메서드는 더이상 읽을 라인이 없을 경우 null을 리턴

 

BufferedReader 와 BufferedWriter는 버퍼를 사용해 파일 입출력을 해서 속도가 향상된다

import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("b.txt")); // FileReader 를 사용해서 읽어온 내용을 출력 // 내용이 채워져 있는 텍스트 파일을 사용하면 출력 결과를 볼 수 있습니다. String str; while((str = br.readLine()) != null){ // readline 메소드는 한줄씩 읽어서 출력, while 문에서 null 이 될 때까지 반복 System.out.println(str); } br.close(); } }

 

 

import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter( new FileWriter("copied_b.txt")); BufferedReader br = new BufferedReader( new FileReader("b.txt")); String str; while((str = br.readLine()) != null){ System.out.println(str); bw.write(str + "\n"); } br.close(); bw.close(); } } // b.txt 파일을 읽어서 copied_b.txt 파일에 복사 // 파일을 읽어서 파일에 씁니다.(파일을 읽는 클래스와 파일을 쓰는 클래스를 사용)

 

+

버퍼를 사용하지 않는 입력은 키보드의 입력이 키를 누르는 즉시 바로 프로그램에 전달되며,

버퍼를 사용하는 입력은 키보드의 입력이 있을 때마다 한 문자씩 버퍼에 전송한다.

(버퍼가 가득 차거나 혹은 개행 문자가 나타나면 버퍼의 내용을 한번에 프로그램에 전달한다.)

 

BufferedReader는 개행문자만 경계로 인식하고 입력받은 데이터가 String으로 고정

BufferedReader는 동기화 되기 때문에 멀티 쓰레드 환경에서 안전

 

 

<참고>

https://smoothiecoding.kr/%EC%9E%90%EB%B0%94-filewriter-%ED%81%B4%EB%9E%98%EC%8A%A4/

 

자바 FileWriter 클래스 | 자바 입문강좌 56 - 스무디코딩

자바 FileWriter 클래스의 사용법을 알아봅니다. BufferedWriter와 Buffered Reader 도 함께 사용할 수 있습니다. 파일의 복사를 합니다.

smoothiecoding.kr

점프투자바-파일입출력

 

06-01 콘솔 입출력

프로그램을 실행했더니 다음과 같은 문자열이 출력되었다고 가정해 보자. ```no-highlight 생년월일(YYYY/MM/DD)을 입력해 주세요: ``` 이렇게 사용자에게 위…

wikidocs.net

http://www.tcpschool.com/java/java_io_stream

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

https://rlakuku-program.tistory.com/33

 

[Java] 빠른 입출력을 위한 BufferedReader, BufferedWriter, StringTokenizer, StringBuilder

BufferedReader / BufferedWriter BufferedReader와 BufferdWriter는 버퍼를 사용하여 읽기와 쓰기를 하는 함수이다. 버퍼를 사용하지 않는 입력은, 키보드의 입력이 키를 누르는 즉시 바로 프로그램에 전달된다.

rlakuku-program.tistory.com

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.