본문 바로가기
공부/java

16일차 복습

by 샤샤샤샤 2022. 12. 6.

본래 어제 올려야 했으나, 막혔던 문제를 하루종일 붙잡고 있었던 관계로 하루 늦게 작성한다.

 

IO (Input Output) 파일 읽고 쓰기

크게 3종류가 존재한다.

1. 바이트(byte)단위

2. 문자 단위

3. 대용량 - 속도 개선

 

1. 바이트 단위 파일쓰기

FileOutputStream 클래스: 주어진 file객체가 가르키는 파일을, 바이트 스트림으로 읽기 위한 클래스. 객체를 생성할때                                                  FileOutputStream ( file ) 형식의 생성자 함수값을 넣어줘야 한다.

                                           파일 경로를 넣어줄 수 도 있고, 파일이름을 넣을 수도 있다.

public class ex121 {
    public static void main(String[] args) {

            String filePath = "./out1.txt";   ** out.txt파일은 본래 없으나, 이 코드가
                                              ** 실행되면서 저절로 생긴다.
       try {
            FileOutputStream fos = new FileOutputStream(filePath);
           String data = "파일에 문자열 쓰기\r\n";
           fos.write( data.getBytes() );
           fos.close()
            }catch ( Exception e ) {
            System.out.println("파일 입출력 에러");
            e.printStackTrace();            // 에러 내용 보기
        }
    }
}

위의 코드를 보자. 파일 경로를 지정한 변수 filePath가 존재한다.

여기서 " . " 은 현재 파일을 말한다. 즉, 내가 코드를 적고 있는 java파일이 있는 경로가 된다.

out1.txt는 본래 없는 파일이었으나, 이 코드를 실행하면 저절로 생긴다. 파일의 형식과 이름을 지정한 것이다.

 

문자열 뒤에 붙은 \r 은 현재 커서를 의미한다. 여기서 커서란, 마우스 커서가 아닌 문자열 커서, 자판을 칠 때 문자가 써질 위치를 표시하는 깜박거리는 | 표시를 말한다.

\r\n : 줄바꿈 표시. 이 파일에서는 티가 나지 않지만, 만약 줄이 바뀌는 글을 쓴다면 이 명령어들을 꼭 넣어줘야 줄이 의도             대로 바뀐다.

fow.wirte() : 글을 적기 위한 함수다.

.getBytes() : 문자열을 byte코드로 바꿔서 전환(인코딩)하는 역할을 한다. UTF-8이나 다양한 인코딩(캐릭터셋) 형식을 넣                         을수 있다.

                     캐릭터셋을 지정하지 않으면 플렛폼의 기본 형식으로 인코딩된다. 이경우, 정보 손상이 일어날 위험이 있다.

                                                            *** 캐릭터 셋과 인코딩의 차이****

같은 의미라고 이해하면 편하다. 문자의 복호화, 즉 숫자로 표현하는 것을 의미한다.

 

try{ } catch{ } : 파일을 쓰는 모든 방법은 try/catch로 감싸줘야만 한다. 이는 아래 나올 2가지 방법도 마찬가지다.

 

 

 

 

그럼 여기에 filepath대신 파일 이름을 넣어보자. 위에서 만들어진 out1.txt를 사용하겠다.

import java.io.FileOutputStream;

public class asdfasasgqwr {
    public static void main(String[] args) {
        try {
            FileOutputStream fos = new FileOutputStream("out1.txt");
            String data = "파일에 문자열 쓰기2\r\n";
            fos.write(data.getBytes("UTF-8"));
            fos.close();   // 버퍼 메모리 정리
        } catch (Exception e) {
            System.out.println("파일 입출력 에러");
            e.printStackTrace();
        }
    }
}

이번에는 getBytes()에 어떤 인자도 넣지 않았다.

이 경우, 먼저 있던 out1.txt의 내용물은 어떻게 될까? 확인해보자.

다행히 문자열이 깨지지는 않았지만, 먼저 있던 내용물이 사라지고 새로운 내용이 덮어 씌워진 것을 확인할 수 있다.

 

2. 문자 단위 파일 쓰기

FileWriter클래스를 사용한다.

FileWriter 클래스 : 이어쓰는게 가능한 파일 쓰기 방식이다. 다만 기록하고자 하는 파일의 크기가 100k를 넘어가면 성능이                                 하락한다.

import java.io.FileWriter;
public class IOTest {
    public static void main(String[] args) {
        String txt = "fileWriter 테스트!!" ;
        try{
            // true 지정시 파일의 기존 내용에 이어서 작성
            FileWriter fw = new FileWriter("out1.txt", true) ;
            // 파일안에 문자열 쓰기
            fw.write(txt);
            // 버퍼 밀어내기
            fw.flush();
            // 객체 닫기
            fw.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

결과:

만약 true값을 넣지 않고 그냥 썻다면 덮어썼을 것이다.

 

주목할 것은 fw.flush() 함수다.

flush( ) : 버퍼 메모리를 전부 밀어낸다. 이 경우에는  write() 함수를 사용했기에, 처리되지 않고 남아있는 데이터를 write()                  함수로 처리한다.

              언뜻 들으면 flush()를 사용하지 않으면 데이터가 손상되나 싶지만, 그것은 아니다. 이미 cpu에서 연산을 마쳤더                  라도, 물리적으로 저장되지 않은 데이터를 강제로 처리하는 함수라고 이해하면 된다. 

              따라서 앞서 통신으로 데이터를 보냈다면 남은 버퍼를 통신으로 보내는 역할을 하고, 저장했다면 남은 버퍼를                      저장하는 역할을 하는 식이다.

 

3. BufferedWriter 클래스 : 100k바이트 이상의 파일을 쓸때 사용한다. Buffer은 입출력 속도에 따른 여유 메모리 공간을 말                                            한다.

사용법

BufferedWriter은 FileWriter의 단점을 보안하기 위해 나온 클래스인 만큼, FileWriter의 객체를 매개변수값으로 받는다.

import java.io.BufferedWriter;
import java.io.FileWriter;

public class IOTest {
    public static void main(String[] args) {
        String filePath = "./out1.txt";
        try {
            FileWriter fw = new FileWriter(filePath,true);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write("춘향이\r\n");
            bw.newLine(); //빈줄 추가
            bw.write("홍길동\r\n");
            bw.write("이강인\r\n");
            bw.close();
        } catch (Exception e) {
            System.out.println("파일입출력 에러!");
            e.printStackTrace();
        }
    }
}

FileWriter 클래스의 객체를 만든 다음, BufferedWriter 클래스 객체 생성의 매개변수로 넣었다.

 

결과

true값을 준 덕에 덮어씌워지지는 않았으나, 이전에 쓴 글과 "춘향이" 같은 줄에 출력되었다.

이는 이전 코드에서 "fileWriter테스트!!" 문자열을 쓸때, \r\n을 통해 문자열을 변경해주지 않았기 때문이다.

 

 

파일 읽기

읽는 방식 역시 쓰기와 마찬가지로 3가지 종류가 있다.

파일을 옳바르게 읽기 위해선 현재 읽고 있는 곳이 파일이 끝인지 아닌지 확인해야만 하는데, 컴퓨터는 인간이 아니므로 글의 내용으로는 확인이 불가능하다.

따라서 컴퓨터는 파일을 읽어들일때 더이상 읽어들일 거리가 없다면, 즉 파일의 끝(End Of File)에 도달한다면, -1의 값을 반환한다.

 

1. 바이트 단위 읽기

import java.io.FileInputStream;

public class IOTest {
    public static void main(String[] args) throws Exception {
        String filePath = "./out1.txt";
        FileInputStream fis = new FileInputStream(filePath);
        int data = 0; //읽은 바이트 데이타를 저장하는 용도
        //do-while()문 : 적어도 한번은 수행하고 조건에 따라 반복!
        do {
            data = fis.read(); //1바이트를 읽어들임.
            if (data != -1) {
                System.out.print((char) data);
            }
        }
        while (data != -1); //파일의 끝(eof)에 도달할때 탈출
        fis.close();
    }
}

read() : 1바이트씩 데이터를 읽어오는 함수.

 

do-while()문을 이용해 문자를 1바이트씩 읽어오다 -1이 나오면 탈출하는 논리다.

이 경우 출력값은 어떻게 될지 확인해보자.

글자가 다 깨져서 보인다. 한글을 적절하게 디코딩하지 못한 탓이다.

이를 해결하기 위해서는 따로 IO 라이브러리를 임포트해, 출력 인코딩 타입을 지정하면 된다. 허나 여기서 다루지는 않을 것이다.

 

2. FileReader 클래스 사용

FileInputStream 과 똑같이 읽을수 있다.

import java.io.FileReader;

public class IOTest {
    public static void main(String[] args) throws Exception {
        String filePath = "./out1.txt";
        FileReader fis = new FileReader(filePath);
        int data = 0; //읽은 바이트 데이타를 저장하는 용도
        //do-while()문 : 적어도 한번은 수행하고 조건에 따라 반복!
        do {
            data = fis.read(); //1바이트를 읽어들임.
            if (data != -1) {
                System.out.print((char) data);
            }
        }
        while (data != -1); //파일의 끝(eof)은 -1
        fis.close();
    }
}

FileInputStream 객체 대신 FileReader 객체를 만든것 이외에는 변한게 없다.

이경우 출력문은 어떤 식으로 나올까

이 경우에는 한글이 깨지지 않고 잘 출력되었다.

차이는 바로 읽어들이는 단위에 있다.

FileOutputStream 클래스는 1바이트가 오는데로 바로 해석해서 문자를 출력한다. 반면 FileReader클래스는 2바이트를 합쳐 유니코드 단위로 해석하는데, 한글은 다른 나라 문자와는 다르게 한글자가 2바이트의 용량을 차지한다. 따라서 유니코드 단위로 해석하는 FileReader 클래스는 깨지지 않는 것이다.

 

3. BufferedReader 클래스

이번에는 한글자씩이 아닌 한 문장씩 출력해보자.

import java.io.BufferedReader;
import java.io.FileReader;

public class IOTest {
    public static void main(String[] args) throws Exception {
        String filename = "out1.txt";
        FileReader fr = new FileReader(filename);
        BufferedReader br = new BufferedReader(fr);
        String text = "";
        while (text != null) {
            text = br.readLine();      // readLine() : 한 줄씩 읽음
            System.out.println(text);
        }
        br.close();
    }
}

결과

 

이 역시 쓰기와 마찬가지로 FileReader 클래스의 객체를 매개변수로 주면서 선언한다.

주목할점은 readLine() 함수와 null값이다.

readLine() 함수는 한줄씩 읽어오는 일을 한다. 따라서 위의 두 예제와 같은 결과물이 출력되었지만, 그 구동방식은 BufferedReader이 훨씬 더 빠르다고 할 수 있다.

 

또한 마지막값으로 null이 나왔는데, 이는 더이상 읽을게 없는 파일의 끝에 도달하면 출력하는 값이다. 바이트단위에서 -1을 출력하던 것과 같은 역할을 한다.

 

 

 

통신

겉핥기로나마 기본을 배웠다. 일단 배웠으니 정리한다.

 

IP주소: 인터넷상의 주소. 일반적으로 32비트짜리 IP v4를 쓰지만 현대에 들어오면서 할당된 43억개가량의 주소가 모두 소진되었기에 새로운 128비트짜리 IP v6가 나왔다.

 

내 IP주소 확인하기.

cmd혹은 powershell 에서 ipconfig 명령어로 구할수 있다.

복사는 insert + cntrl로 할수 있으며, 붙여넣기는 shift + insert로 가능하다.

 

두종류의 ip주소

1. 공인 ip주소

고정과 유동

고정은 가격이 비싸지만 ip가 절대 변하지 않는다. 반면 유동은 가격도 싸고 컴퓨터를 재부팅할때마다 변한다.

 

2. 사설ip주소

유무선 공유기(허브, 라우터) 에서 ip를 가상으로 할당해서 내부적으로만 사용한다

 

InetAddress클래스

이 클래스는 싱글톤이기에 new를 사용하지 않고 객체를 만들수 있으나, 단 하나밖에 못만든다. 따라서 기존의 클래스들과 달리 클래스 자체가 아닌, 클래스의 매서드값을 객체로 삼는다.

 

 

getLocalHost() : 자신의 ip주소를 얻어오는 함수

InetAddress localhost = InetAddress.getLocalHost();  // 싱글톤이기에new가 없다.
결과값: 192.***.***.*** 자기 컴퓨터의 주소

getAllByName() : 도매인 주소를 통해 도매인의 ip주소 얻어오는 함수. 배열 형식이기에 for문을 통해 출력한다.

InetAddress[] iaAddress = InetAddress.getAllByName("www.daum.net");
for( InetAddress remote : iaAddress ){
      System.out.println("daum ip : " + remote.getHostAddress() );
 System.out.println("naem : " + remote.getHostName() );
 결과: 121.53.105.193  // daum의 ip 주소 중 하나

이후 나올 통신에 대한 내용들은 다른 글에서 다루겠다.

'공부 > java' 카테고리의 다른 글

18일차 복습  (0) 2022.12.08
16-17일 통신  (0) 2022.12.06
15일차 복습  (0) 2022.12.04
14일차 복습  (0) 2022.12.01
13일차  (0) 2022.11.30