。゚(*´□`)゚。

코딩의 즐거움과 도전, 그리고 일상의 소소한 순간들이 어우러진 블로그

[네이버클라우드] 클라우드 기반의 개발자 과정 7기/웹프로그래밍

[NC7기-54일차(7월11일)] - 웹프로그래밍 35일차

quarrrter 2023. 7. 11. 17:30

40. 프로젝트에 예외처리 적용

try~catch~finally

 

server app - DAO 메서드 호출할 때 try 적용 

client app  - execute 적용 


41. 여러 클라이언트의 요청을 순차적으로 처리하기 : Stateful 방식 

- 클라이언트 요청을 순차적으로 처리하는 방법 

먼저 접속한 클라이언트가 접속을 끊을때까지 대기. 

 

유튜브 실시간 채팅 & 게임

특징

1. 접속 후 연결 상태로 유지한다. -> 서버 자원을 점유 -> 동시 많은 클라이언트 접속을 유지할 수 없다.(stateless에 비해)

2. 클라이언트 정보를 유지하기 때문에 -> 클라이언트가 요청한 작업 결과 유지 -> 연결작업을 처리하기 수월하다.

 

while로 무한 루프 server앱 소켓부분 

 

try ~ catch문 안에 또 try~catch 들어가도 됨 ! 중복 가능 

 

try 문안에 선언된건 try 바깥에서 못 씀. 

 

finally { // close도 예외 발생하는 메서드 , 소켓을 닫아야하니까 각각 따로 해야함.

try {in.close();} catch (Exception e) {}

try {out.close();} catch (Exception e) {}

try {socket.close();} catch (Exception e) {}

}

 

= try with resources

try(Socket s = socket; DataInputStream in = new DataInputStream(socket.getInputStream());

DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {

 

//Socket s = socket close를 위해 새로 넣은 것. try () 안 마지막코드는 ; 안 붙여도 됨

// 파라미터 값 먼저 돌고 본 코드 돌아감 


42. 여러 클라이언트의 요청을 순차적으로 처리하기 : Stateless 방식 

 

한 번에 작업 한 개 ex)114 안내전화, HTTP(웹), 메신져

특징:

1. 요청할 때마다 매번 연결 -> 요청시간이 길어짐/(연결시간이 포함되기 때문에) -> 클라이언트 작업 결과를 유지할 수 없음 -> 연결 작업을 수행하기 어렵다(매번 연결하기 때문에, 서버는 클라이언트를 식별하기 힘들다.)

2. 응답 후 클라이언트와 연결을 끊는다. -> 서버에 클라이언트 정보를 유지하지 않는다. -> 서버 자원을 덜 사용한다.(statefull에 비해) -> statefull 보다 같은 하드웨어를 가지고 더 많은 클라이언트 동시 접속 처리 가능 

 

serverapp 수정

클라이언트 DaoBuilder

client 수정


43. 여러 클라이언트 요청을 동시에 처리하기: Thread 적용 

스레드의 구동원리와 사용법 

- 스레드의 라이프사이클 이해

- 스레드 클래스와 Runnable 인터페이스 사용법 

멀티태스킹의 메커니즘 이해

- 프로세스 스케쥴링: Round robin 방식, priority + Aging 방식 

- 컨텍스트 스위칭

- 프로세스 복제(fork)방식과 스레드 방식 비교

- 임계영역(Critical region), 세마포어(Semaphore) 와 뮤텍스(Mutex)

 

 

대기열은 큐 방식이라  c1정보는 대기열에서 제거된다.

// 상대편으로부터 연결 요청 받기 - 서버(server)
public class Receiver {

  public static void main(String[] args) throws Exception {
    System.out.println("서버 실행!");

    // 1) 다른 컴퓨터의 연결 요청을 기다린다.
    // - new ServerSocket(포트번호)
    // - 포트번호: 
    //   - 호스트에서 실행 중인 서버 프로그램을 구분하는 번호이다.
    //   - 1024 ~ 49151 사이의 값 사용한다.
    //      - 1 ~ 1023 사이의 포트 번호는 특정 서버가 사용하기 위해 미리 예약된 번호다.
    //      - 가능한 이 범위의 포트 번호는 사용하지 않는 것이 좋다.
    //   - 유명 프로그램의 포트 번호도 가능한 사용하지 말라.
    //      - 예) Oracle DBMS(1521), MySQL DBMS(3306) 등
    //   - 같은 컴퓨터에서 다른 프로그램이 이미 사용중인 포트 번호는 지정할 수 없다.
    //      - 포트 번호는 중복으로 사용될 수 없다.
    ServerSocket serverSocket = new ServerSocket(8888);
    System.out.println("ServerSocket 생성!");

    // 2) 연결을 기다리고 있는 클라이언트가 있다면 맨 먼저 접속한 클라이언트의 연결을 승인한다. 
    // - 클라이언트가 서버에 접속을 요청하면 그 정보를 "대기열"이라고 불리는 목록으로 관리한다.
    // - accept()를 호출하면 대기열에서 순서대로 꺼내 해당 클라이언트와 연결된 소켓을 만든다.
    Socket socket = serverSocket.accept();
    System.out.println("클라이언트와 연결된 Socket 생성!");

    // 3) 소켓 객체를 통해 읽고 쓸 수 있도록 입출력 스트림을 얻는다.
    // - 연결된 클라이언트로 데이터를 보내고 받으려면 입출력 스트림을 꺼내야 한다.
    // - 소켓이 리턴해준 입출력 스트림에 적절한 데코레이터를 붙여서 사용한다.
    PrintStream out = new PrintStream(socket.getOutputStream());
    Scanner in = new Scanner(socket.getInputStream());
    System.out.println("데이터 송수신을 위한 입출력 스트림 준비!");

    // 4) 상대편이 보낸 문자열을 한 줄 읽는다.
    // => 상대편이 한 줄의 데이터를 보낼 때까지 리턴하지 않는다.
    // => 이런 메서드를 블로킹 메서드라 부른다.
    String str = in.nextLine();
    System.out.printf("상대편> %s\n", str);

    // 5) 상대편으로 문자열을 한 줄 보낸다.
    out.println("나는 엄진영입니다. 반갑습니다!");

    // 6) 항상 입출력 도구는 사용 후 닫아야 한다.
    in.close();
    out.close();

    // 7) 네트워크 연결도 닫는다.
    socket.close(); // 클라이언트와 연결을 끊는다.
    serverSocket.close(); // 클라이언트의 연결 요청을 받지 않는다.

  }

}
// 상대편에 연결을 요청하기 - 클라이언트(client)
public class Sender {

  public static void main(String[] args) throws Exception {
    System.out.println("클라이언트 실행!");

    // 1) 다른 컴퓨터와 네트워크로 연결한다.
    // => 서버와 연결되면 Socket 객체가 생성된다.
    // => 서버와 연결될 때까지 리턴하지 않는다.
    // => 서버에 연결할 수 없으면 예외가 발생한다.
    //    - 기본으로 설정된 타임아웃 시간까지 연결되지 않으면 예외가 발생한다.
    // 
    // new Socket(원격 호스트의 IP 주소/도메인이름, 원격 호스트 프로그램의 포트번호)
    //    - 로컬 호스트(애플리케이션을 실행하는 현재 컴퓨터)일 경우: 127.0.0.1 또는 localhost
    Socket socket = new Socket("localhost", 8888); // 서버의 대기열에 등록된다면 리턴한다.
    System.out.println("서버와 연결된 Socket 생성!");

    // 2) 소켓 객체를 통해 읽고 쓸 수 있도록 입출력 스트림을 얻는다.
    PrintStream out = new PrintStream(socket.getOutputStream());
    Scanner in = new Scanner(socket.getInputStream());
    System.out.println("서버와 데이터를 송수신할 스트림 준비!");

    // 3) 상대편으로 문자열을 한 줄 보낸다.
    // => 보낸 데이터는 NIC의 메모리에 임시 보관된다. 
    // => 임시 보관된 데이터가 상대편으로 완전히 보내졌는지 따지지 않고 즉시 리턴한다.  
    out.println("엄진영입니다. 안녕하세요!");

    // 4) 상대편에서 보낸 문자열을 한 줄 읽는다.
    // => 상대편이 한 줄 데이터를 보낼 때까지 리턴하지 않는다.
    // => 이런 메서드를 블로킹 메서드라 부른다.
    String str = in.nextLine();
    System.out.println(str);

    // 5) 항상 입출력 도구는 사용 후 닫아야 한다.
    in.close();
    out.close();

    // 6) 네트워크 연결도 닫는다.
    socket.close();

  }

}

println 한다고 해서 데이터가 보내지는게 아님

 

프로토콜: 통신 규칙 

버퍼사용해서 통신하기 sender 5 


서버 만들기 

 System.out.println("서버 실행!");
    // 1) 네트워크 연결을 기다리는 역할을 수행할 객체를 준비
    // => new ServerSocket(포트번호)
    // => 현재 실행 중인 프로그램과 포트 번호가 중복되어서는 안된다.
    ServerSocket ss = new ServerSocket(8888);
    // 포트번호
    // => 한 컴퓨터에서 네트워크 연결을 기다리는 프로그램의 식별번호이다.
    // => OS는 이 번호를 가지고 데이터를 받을 프로그램을 결정한다.

    System.out.println("클라이언트 연결을 기다리는 중...");

    // 잠깐 멈추기
    keyboard.nextLine(); // 사용자가 엔터를 칠 때까지 리턴하지 않는다.

    ss.close();
    System.out.println("서버 종료!");

클라이언트 만들기

  public static void main(String[] args) throws Exception {
  
    // 1) 서버에 연결 요청을 할 때 사용할 도구를 준비한다.
    // => 서버와의 연결이 이루어지면 Socket 객체를 리턴한다.
    // => 클라이언트 측의 포트 번호는 OS가 자동으로 부여한다.
    //    서버 측은 개발자가 명시적으로 부여해야 한다.
    Socket socket = new Socket(
        // 서버 IP 주소(ex: 234.3.4.56) 또는 도메인명(ex: www.daum.net)
        "localhost", 
        // 특수 IP : 127.0.0.1 - 로컬 컴퓨터를 가리킨다.
        // 특수 도메인명 : localhost - 127.0.0.1을 가리킨다.
        //

        // 서버 포트번호 - 서버를 구분하는 식별 번호.
        8888 
        // IP 주소가 회사 대표 번호라면, 포트 번호는 내선 번호라 할 수 있다.
        );
    System.out.println("서버와 연결되었음!");

    // 2) 서버와 연결 해제
    // => 작업이 끝난 후에는 항상 서버와의 연결을 해제해야 한다.
    // => 물론 해제하지 않아도 서버측에서 일정 시간이 지나면 자동으로 연결과 관련된 자원을 해제한다.
    // => 그러나 가능한 명시적으로 연결을 해제하는 것이 좋다. 자원회수 및 다음 사용자위해
    //
    socket.close();
    System.out.println("서버와 연결을 끊었음!");

대기열? 클라이언트 몇명까지 대기할지 허락하는. 

=> 클라이언트가 접속을 요청하면 대기열에 클라이언트 정보를 저장한다.

=> 저장은 큐(FIFO) 방식으로 관리한다.

=> 대기열의 크기가 클라이언트의 연결을 허락하는 최대 개수이다.

=> 대기열을 초과하여 클라이언트 요청을 들어 왔을 때 서버는 응답하지 않는다.

클라이언트는 내부에 설정된 시간(timeout)동안 기다리다 응답을 받지 못하면

예외를 던지고 연결 요청을 취소한다.

=> new ServerSocket(포트번호, 대기열크기);

다음과 같이 대기열의 개수를 지정하지 않으면, 기본이 50개이다. ==> 클라이언트 50개까지 줄 세울 수 있다는 소리. 

ServerSocket ss = new ServerSocket(8888);

ServerSocket ss = new ServerSocket(8888, 2);  //2 :백로그 : 접속할 수 있는 최대 갯수

로컬에서 할 땐 바로 오류뜨지만 원격인 경우엔 일정시간 후 오류 뜸... 

 

 

타임아웃 에러 / 타임아웃 시간 설정하기

    // 실행을 잠시 중단시키기 위해 사용
    Scanner keyScan = new Scanner(System.in);
    System.out.println("클라이언트 실행!");

    // 1) 소켓을 생성한다.
    Socket socket = new Socket();

    // 2) 연결할 서버의 주소를 준비한다. 
    SocketAddress socketAddress = new InetSocketAddress("192.168.0.xx", 8888);

    // 3) 서버와의 연결을 시도한다.
    // => 타임아웃으로 지정된 시간 안에 서버가 승인(accept())하지 않으면 즉시 예외가 발생한다.
    // => Windows의 경우, 
    //    - 로컬에 접속할 때 타임아웃 설정이 정상적으로 동작되지 않는다.(확인 할 것!)
    //    - 원격 윈도우 PC에 서버를 실행하여 접속한다면 정상적으로 동작한다.

    socket.connect(socketAddress, 10000); // timeout : milliseconds

    keyScan.nextLine(); // 사용자가 엔터를 칠 때까지 다음 코드로 이동하지 않는다.

    socket.close();
    keyScan.close();

 

 

대기열에서 accept로 꺼내지면 대기열 비어짐.

    Scanner keyboard = new Scanner(System.in);

    ServerSocket ss = new ServerSocket(8888, 2);

    // 테스트1) 대기열에 클라이언트가 없을 때,
    // => accept()는 블로킹 상태에 놓인다.
    //    즉 리턴하지 않는다.

    // 큐(queue)에 대기중인 클라이언트 중 첫 번째 클라이언트를 꺼내서 연결을 승인한다.
    // => 클라이언트가 서버에 연결을 요청하면, 서버는 대기열에 추가한다.
    // => 서버소켓에서 연결을 승인하면 클라이언트와 통신할 수 있는 소켓을 리턴한다.
    // => 대기열에 기다리고 있는 클라이언트가 없으면 접속할 때까지 기다린다.
    Socket socket = ss.accept();

    keyboard.nextLine();
    
    socket.close();
    ss.close();
    keyboard.close();

 

 

일반 문장으로 try with resources에 넣을 수 없으니까 문장 출력 후 try문 또 만들어서 socket 넣

byte 배열

    try (Socket socket = new Socket("localhost", 8888);
        OutputStream out = socket.getOutputStream();
        InputStream in = socket.getInputStream()) {

      // 서버에 데이터를 보내기 전에 잠깐 멈춤!
      keyScan.nextLine();

      // 서버에 보낼 바이트 배열을 준비한다.  => 0 ~ 99 의 값을 가진 배열이다.
      byte[] bytes = new byte[100];
      for (int i = 0; i < 100; i++) {
        bytes[i] = (byte) i;
      }

      // 서버에 바이트 배열을 전송한다.
      out.write(bytes);
      // out.flush();
      // byte stream 을 사용할 때는 바로 출력한다. 따라서 flush()를 호출하지 않아도 된다.

클라이언트앱은 들어온 순서대로 읽어오면 됨. 

 

printStream (출력 스트림임) // 비추

한줄 읽기 , out.flush() 필요 없음 

try (Socket socket = serverSocket.accept();

Scanner in = new Scanner(socket.getInputStream());

PrintStream out = new PrintStream(socket.getOutputStream())) { ) // 비추 

 

byte stream + buffer

데이터를 보내기 위해 반드시 flush()를 호출해야 한다.

flush 전에는 데이터가 버퍼에 저장되고, flush 후에 서버에 전달됨.

bufferedOutputStream 주의 !! 

 

프린터 스트림은 바이트 스트림

프린터 라이터는 캐릭터스트림

character stream(print writer + println) - byte stream 반드시 flush 호출해야함

 

character stream 클래스의 경우
      // 출력 데이터를 내부 버퍼에 보관하고 있다가 버퍼가 꽉차거나 flush()를 호출할 때 출력을 수행한다.
      // - BufferedWriter를 붙이지 않아도 이렇게 동작하기 때문에 주의하라!

 


character stream

character stream - 문자 단위로 출력하기

0x 7a5f0041 write() FileOutputStream 00(1byte)
41(1byte)

=> byte stream은 변환없이 1byte를 그대로 출력함
0x 7a6bac00
JVM은 문자 데이터를 다룰 때 UCS2(UTF16BE, 2바이트) 유니코드를 사용
write() FileWriter AC00(2byte)
 - JVM Argument  file.encoding =utf-8 / Ms 949 / EUC-KR

지정된 방식으로 변환됨
eab080

 
=> character stream은 UCS2를 UTF-8로 변환하여 출력 

    // UCS2에서 한글 '가'는 ac00이다.
out.write(0x7a6bac00);
// - 앞의 2바이트(7a6b)는 버린다.
// - 뒤의 2바이트(ac00)은 UTF-8(eab080) 코드 값으로 변환되어 파일에 출력된다.


// UCS2에서 영어 A는 0041이다.
// 출력하면, UTF-8 코드 값(41)이 파일에 출력된다.
out.write(0x7a5f0041); //
// - 앞의 2바이트(7a5f)는 버린다.
// - 뒤의 2바이트(0041)는 UTF-8(41) 코드 값으로 변환되어 파일에 출력된다.

file encoding 옵션을 설정하지 않으면 어떤os 에 출력하느냐에 따라 출력 코드가 달라짐 
 java-w exe : 윈도우에서 쓰는 JVM

텍스트 파일이 아닌 바이너리파일을 reader writer로 읽으면 큰일남 

reader writer는 출력할때 원본데이터 안 따지고 UCS2 방식으로 앞에꺼 짤라버리고 뒤에 2바이트만 읽어버려서 ; 

 

character stream - 문자 단위로 출력하기

JVM의 문자열을 파일로 출력할 때
// FileOutputStream 과 같은 바이트 스트림 클래스를 사용하면 문자집합을 지정해야 하는 번거로움이 있었다.
// => 이런 번거로움을 해결하기 위해 만든 스트림 클래스가 있으니, 문자 스트림 클래스이다.
// => Reader/Writer 계열의 클래스이다.


// 1) 문자 단위로 출력할 도구 준비
FileWriter out = new FileWriter("temp/test2.txt");


// 2) 문자 출력하기
// - JVM은 문자 데이터를 다룰 때 UCS2(UTF16BE, 2바이트) 유니코드를 사용한다.
// - character stream 클래스 FileWriter는 문자 데이터를 출력할 때
// UCS2 코드를 JVM 환경변수 file.encoding 에 설정된 character set 코드로 변환하여 출력한다.
// - JVM을 실행할 때 -Dfile.encoding=문자집합 옵션으로 기본 문자 집합을 설정한다.
// 만약 file.encoding 옵션을 설정하지 않으면 OS의 기본 문자집합으로 자동 설정된다.
//
// Linux, macOS 의 기본 character set => UTF-8
// Windows 의 기본 character set => MS-949
//
// - OS에 상관없이 동일한 character set으로 출력하고 싶다면
// JVM을 실행할 때 file.encoding 프로퍼티에 character set 이름을 지정하라.
//
// - JVM을 실행할 때 출력 데이터의 문자 코드표를 지정하는 방법
// java -Dfile.encoding=문자코드표 -cp 클래스경로 클래스명
// 예) java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.io.ex03.Exam0110
//
// - 단, character set을 지정할 때는 해당 OS에서 사용가능한 문자표이어야 한다.
// MS Windows에서는 ms949 문자표를 사용할 수 있지만,
// 리눅스나 macOS에서는 국제 표준이 아니기 때문에 ms949 문자표를 사용할 수 없다.
//
// [결론]
// - OS에 영향 받지 않으려면,
// JVM을 실행할 때 반드시 file.encoding JVM 환경 변수를 설정하라.
// - 문자집합은 UTF-8을 사용하라.
// - 국제 표준이다.
// - linux, macOS의 기본 문자 집합이다.
//


// 현재 JVM 환경 변수 'file.encoding' 값 알아내기
System.out.printf("file.encoding=%s\n", System.getProperty("file.encoding"));

out.close();

} }

 

character stream - 문자 단위로 읽기

 

Filereader : 중간 변환 과정 有

 

character stream - 문자 단위로 읽기

    // 1) 파일의 데이터를 읽는 일을 하는 객체를 준비한다.
    FileReader in = new FileReader("sample/utf8.txt"); // 41 42 ea b0 81 ea b0 81

    // 2) JVM 환경 변수 'file.encoding'에 설정된 문자코드표에 따라
    //    바이트를 읽어서 UCS2로 바꾼 후에 리턴한다.

    // file.encoding이 UTF-8로 되어 있다면,
    // => 영어는 1바이트를 읽어서 2바이트 UCS2로 변환한다.
    int ch1 = in.read(); // 41 => 0041('A')
    int ch2 = in.read(); // 42 => 0042('B')

    // => 한글은 3바이트를 읽어서 2바이트 UCS2로 변환한다.
    int ch3 = in.read(); // ea b0 80 => ac00('가')
    int ch4 = in.read(); // ea b0 81 => ac01('각')

    // 3) 읽기 도구를 닫는다.
    in.close();

 

utf-8말고 다른 방식으로 읽고 싶으면 ,,!  팩토리메서드 선언 

=> 출력 스트림 객체를 생성할 때 문자 집합을 지정하면  UCS2 문자열을 해당 문자집합으로 인코딩 한다.
Charset charset = Charset.forName("EUC-KR");  // 팩토리 메서드 
FileWriter out = new FileWriter("temp/test2.txt", charset);

□ System.out.println(Charset.isSupported("EUC-KR"));  // EUC-KR 제공하는지 확인 

 

 

Character Stream - 문자 배열 출력하기

    FileWriter out = new FileWriter("temp/test2.txt");

    char[] chars = new char[] {'A', 'B', 'C', '0', '1', '2', '가', '각', '간', '똘', '똥'};

    // FileOutputStream 은 byte[] 을 출력하지만,
    // FileWriter 는 char[] 을 출력한다.
    out.write(chars); // 문자 배열 전체를 출력한다.

    // 당연히 UCS2를 JVM 환경 변수 'file.encoding'에 설정된 문자 코드표에 따라 변환하여 출력한다.
    // JVM이 입출력 문자 코드표로 UTF-8을 사용한다면
    // 영어는 1바이트로 변환되어 출력될 것이고,
    // 한글은 3바이트로 변환되어 출력될 것이다.
    // JVM(UCS2)    File(UTF-8)
    // 00 41    ==> 41
    // 00 42    ==> 42
    // 00 43    ==> 43
    // 00 30    ==> 30
    // 00 31    ==> 31
    // 00 32    ==> 32
    // ac 00    ==> ea b0 80
    // ac 01    ==> ea b0 81
    // ac 04    ==> ea b0 84
    // b6 18    ==> eb 98 98
    // b6 25    ==> eb 98 a5
    out.close();

8로 내보내고 

16으로 읽음

 

Character Stream - 문자 배열 읽기

  public static void main(String[] args) throws Exception {
    FileReader in = new FileReader("temp/test2.txt");

    // UCS2 문자 코드 값을 저장할 배열을 준비한다.
    // => 이렇게 임시 데이터를 저장하기 위해 만든 바이트 배열을 보통 "버퍼(buffer)"라 한다.
    char[] buf = new char[100];

    // read(버퍼의주소)
    // => 버퍼가 꽉 찰 때까지 읽는다.
    // => 물론 버퍼 크기보다 파일의 데이터가 적으면 파일을 모두 읽어 버퍼에 저장한다.
    // => 리턴 값은 읽은 문자의 개수이다. 바이트의 개수가 아니다!!!!!
    //    FileInputStream.read()의 리턴 값은 읽은 바이트의 개수였다.
    // => 파일을 읽을 때 JVM 환경 변수 'file.encoding'에 설정된 문자코드표에 따라 바이트를 읽는다.
    //    그리고 2바이트 UCS2 코드 값으로 변환하여 리턴한다.
    // => JVM의 문자코드표가 UTF-8이라면,
    //    파일을 읽을 때, 영어나 숫자, 특수기호는 1바이트를 읽어 UCS2으로 변환할 것이고
    //    한글은 3바이트를 읽어 UCS2으로 변환할 것이다.
    int count = in.read(buf);

    // File(UTF-8)  JVM(UCS2)
    // 41       ==> 00 41
    // 42       ==> 00 42
    // 43       ==> 00 43
    // 30       ==> 00 30
    // 31       ==> 00 31
    // 32       ==> 00 32
    // ea b0 80 ==> ac 00
    // ea b0 81 ==> ac 01
    // ea b0 84 ==> ac 04
    // eb 98 98 ==> b6 18
    // eb 98 a5 ==> b6 25

    in.close();

Character Stream - 문자 배열의 특정 부분을 출력하기 

    FileWriter out = new FileWriter("temp/test2.txt");

    char[] chars = new char[] {'A','B','C','가','각','간','똘','똥'}; 

    out.write(chars, 2, 3); // 2번 문자부터 3 개의 문자를 출력한다.

    out.close();

Character Stream - 읽은 데이터를 문자 배열의 특정 위치에 저장하기

    FileReader in = new FileReader("temp/test2.txt");

    char[] buf = new char[100];

    // read(버퍼의주소, 저장할위치, 읽을바이트개수)
    // => 리턴 값은 실제 읽은 문자의 개수이다.
    int count = in.read(buf, 10, 40); // 40개의 문자를 읽어 10번 방부터 저장한다.

    in.close();

 

Character Stream - 텍스트 읽기

    FileReader in = new FileReader("temp/test2.txt");

    // FileReader 객체가 읽을 데이터를 저장할 메모리를 준비한다.
    CharBuffer charBuf = CharBuffer.allocate(100);

    // 읽은 데이터를 CharBuffer 에 저장한다.
    int count = in.read(charBuf);

    in.close();

    // 버퍼의 데이터를 꺼내기 전에 읽은 위치를 0으로 초기화시킨다.
    // - read() 메서드가 파일에서 데이터를 읽어서 버퍼에 채울 때 마다 커서의 위치는 다음으로 이동한다.
    // - 버퍼의 데이터를 읽으려면 커서의 위치를 처음으로 되돌려야 한다.(flip)
    // - flip() 메서드를 호출하여 커서를 처음으로 옮긴다. 그런 후에 버퍼의 텍스를 읽어야 한다.
    charBuf.flip();

    System.out.printf("[%s]\n", charBuf.toString());

 

Character Stream - 텍스트 읽기 II - 한 줄씩 읽을 때 사용

    FileReader in = new FileReader("temp/test2.txt");

    // 데코레이터를 붙인다.
    // => 버퍼 기능 + 한 줄 읽기 기능
    BufferedReader in2 = new BufferedReader(in);

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

    in.close();