//////
Search
🍒

[1006] Set, Map, 파일 입출력, 파일 입출력 코드 리뷰

생성일
2022/11/10 07:58
태그
TodayILearn
java
생성일 1

Set 인터페이스

순서를 유지하지 않는 데이터 집합
데이터 중복을 허용하지 않음
구현 클래스: HashSet, TreeSet

HashSet

: 내부적으로 HashMap을 이용해 만들어진 Set으로, `해싱(Hashing)`을 이용해서 구현
Set 인터페이스를 구현한 `가장 대표적인 컬렉션`
Set 인터페이스의 특징대로 `중복 허용 X`
저장순서를 유지하지 않음 → 순서를 유지하려면 `LinkedHashSet`
메서드
설명
boolean add(Object o)
새로운 객체 삽입
boolean addAll(Collection c)
주어진 컬렉션의 모든 객체 삽입
void clear()
저장된 모든 객체 삭제
boolean contains(Object o)
지정된 객체를 포함하고 있는지 리턴
boolean contains(Collection c)
지정된 컬렉션의 모든 객체를 포함하고 있는지 리턴
boolean isEmpty()
HashSet이 비어있는지 리턴
boolean remove(Object o)
지정된 객체 삭제
boolean removeAll(Collection c)
지정된 컬렉션의 모든 객체 삭제
boolean retainAll(Collection c)
지정된 컬렉션의 모든 객체를 제외한 나머지 삭제
int size()
HashSet에 저장된 객체의 수 리턴

파일 입출력

/*오늘 진도인 파일 읽기만 작성되었습니다*/
파일 입출력의 필요성
코딩을 하다 보면 파일의 데이터를 읽어오는 경우가 있고 ,
읽어온 데이터가 많이 쌓이면 DB에 저장하여 관리합니다.
이 흐름을 따라갈 수 있도록 개발자는 파일의 내용을 읽고 쓰고 출력하는 것에 익숙해져야 합니다.

Stream (시냇물)

스트림은 읽어나 쓸 수 있는 데이터의 흐름을 의미합니다.
모든 입출력 구조는 Stream으로 이루어져 있습니다.
간단히 말하자면 데이터를 운반하는데 사용되는 연결 통로라고도 할 수 있습니다.
스트림은 단방향이기 때문에 입력 스트림, 출력 스트림으로 나뉘어 사용됩니다.
스트림이 처리하는 data type에 따라 Byte 기반 스트림, Character 기반 스트림으로 나뉩니다.

텍스트 파일 읽기

수업 로그(10.06)에 올라온 예제를 통해 설명드리겠습니다.

BufferedReader

BufferedReader/BufferedWriter은 buffer을 사용하기 때문에 FileReader보다 효율적입니다.
Buffer이란? 데이터를 한 곳 에서 다른 곳으로 보낼 때 데이터가 임시로 저장되는 공간.
아래 예시를 보면 버퍼size가 16KB(KB = 1024) 인 BufferedReader객체를 만든다는 의미입니다.
위 그림처럼 한 바이트씩 읽어올 수도 있지만,
아래처럼 readLine()메소드를 통해 텍스트 파일 하나씩 읽을 수 있습니다.
readLine() 메소드
// 텍스트 파일을 한 줄씩 읽어서 return합니다. String str; while ((str = reader.readLine()) != null) { // 더이상 내용이 없으면 null System.out.println(str); }
Java
복사

FileReader

FileReader은 Character 파일을 읽을 수 있는 기능을 제공합니다.
이 클래스는 java.io.InputStreamReader 클래스를 상속받기 때문에, 조상클래스의 멤버 메소드인 read()를 사용하여 char 한 글자씩 읽어올 수 있습니다.
밑의 그림은 문자 하나를 읽어오는 로직입니다.
read() 메소드
public int read() throws IOException
Java
복사
텍스트 파일에서 한 글자씩 글자를 읽어서, 하나의 char을 return합니다.
더이상 읽을 글자가 없으면, -1을 return합니다.
read()사용하여 여러 문자를 출력하는 예시
public class ReadFile { public static void main(String[] args) throws IOException { FileReader reader = new FileReader("D:\\file.txt"); int ch; while ((ch = reader.read()) != -1) { // System.out.print((char) ch); } } }
Java
복사

예외처리

자바는 입력과 출력할 할 때 발생할 수 있는 예외에 대해서 까다롭게 규정하고 있습니다.
Java IOException은 I/O(입력/출력 예외)이며 입력 또는 출력 작업이 실패하거나 해석될 때마다 발생합니다. 
예를 들어 존재하지 않는 파일을 읽으려는 경우 Java는 I/O 예외를 발생시킵니다.
BufferedReader(BufferedWriter) 클래스의 메소드들은 입출력에러가 발생할 경우 자체적으로 IOException을 던지도록 정의되어있기 때문에, 메소드들을 사용할 때 반드시 예외처리를 해주어야 합니다.
테스트를 하고자 할 때 메소드 선언부 옆에 throws IOException을 사용하면 error없이 작성 가능합니다.

File 읽기 코드

자바에서 파일을 읽기 위해 다양한 방법을 활용할 수 있다.
코드를 통해 이러한 방법을 정리하고, 파일을 단계별로 읽어본다.
파일에서 한 글자 읽어오기
파일에서 두 글자 읽어오기
파일에서 N 글자 읽어오기
파일에서 한 줄 읽어오기
파일에서 N 줄 읽어오기
파일을 읽을 때 예외사항이 발생하기 쉽다. 예외를 처리하는 방법도 생각해보자.

File path 설정

파일을 읽기 위해서는 두 가지 조건이 충족되어야 한다.
1.
읽을 수 있는 파일이 존재해야한다.
2.
해당 파일에 접근하기 위해 경로를 알아야 한다.

파일 생성

실습을 위해 파일을 생성하자. 인텔리제이의 자바프로젝트 최상위 폴더에 “afile.txt”을 만들었다.
텍스트 파일 안에는 다음과 같은 내용을 입력하였다.

파일 경로

파일의 경로는 해당 파일을 우클릭한 후 Copy Path/Reference를 클릭하면 알 수 있다.

파일 존재 여부 확인

파일의 경로를 알고 있다고 해도, 실제로 그 파일이 존재하는지 확인할 필요가 있다.
File 클래스를 활용하여 어떤 경로의 파일이 존재하는지 여부를 확인할 수 있다.
1.
파일 한 개 존재 여부 확인
import java.io.File; public class FileExistCheck { public static void main(String[] args) { // File 클래스 활용 File file = new File("C:\\Users\\chanmin\\git\\BackEndSchool2\\afile.txt"); //File file = new File("afile.txt"); if (file.exists()){ System.out.println("파일이 존재합니다."); } else{ System.out.println("파일이 존재하지 않습니다."); } } }
Java
복사
File 클래스 exists()
File 클래스의 생성자는 파일의 경로를 String으로 입력받는다.
File 클래스의 exists() 메소드는 생성자에서 받은 파일 경로에 실제 그 파일이 존재하는지 여부를 boolean으로 반환한다.
인텔리제이에서 File file = new File("afile.txt"); 를 해도 파일이 존재한다는 출력문이 나오는데, 이는 인텔리제이의 Root Directory에 파일이 존재하기 때문이다.
2.
원하는 경로의 모든 파일 목록 확인
import java.io.File; public class DirFileCheck { public static void main(String[] args) { File dir = new File("./"); File[] files = dir.listFiles(); // 현재 디렉토리의 파일 목록 for (File file : files) { System.out.println(file); } }
Java
복사
File 클래스 listFiles()
File 클래스의 listFiles() 메소드 는 생성자에서 받은 파일 경로에 존재하는 모든 파일 목록을 File[] 에 담아 반환한다.
dir 인스턴스를 생성할 때 “/.” 를 전달하였는데, 이는 Root Directory의 경로이다.
for each 문으로 출력하면 현재 디렉토리의 모든 파일 목록을 출력할 수 있다.

파일 읽기

파일이 존재하고 파일의 경로를 알고 있다면, 해당 파일을 직접 읽을 수 있다.
만들어둔 afile.txt 텍스트 파일을 읽는 코드를 작성해보자.
텍스트 파일을 읽기 위해 사용할 수 있는 클래스는 크게 4가지이다.

1. FileReader

FileReader

FileReader는 String fileName을 전달하며 생성할 수 있다.
new FileReader(String fileName);
FileReader는 java.io.InputStreamReader 클래스를 상속받기 때문에, inputStreamReader 클래스의 read() 메소드를 사용하여, char를 한 글자씩 읽어올 수 있다.
read() 메소드는 텍스트 파일에서 한 글자씩 읽어서, int로 아스키코드를 반환한다. 이때 더 이상 글자가 없다면 -1을 반환한다.

파일에서 한 글자 읽기

import java.io.FileReader; import java.io.IOException; public class Read1Letter { public static void main(String[] args) throws IOException { FileReader reader = new FileReader("afile.txt"); char c = (char) reader.read(); System.out.println(c); } /* 출력결과 h */ }
Java
복사
FileReader에 "afile.txt"를 전달해 인스턴스를 생성했다.
read() 메소드를 활용해 "afile.txt"에서 한 글자를 읽었고 이를 char로 형변환해 char c에 초기화했다.
c를 출력하면 h가 나온다.

파일에서 두 글자 읽기

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; // Read2Letter 클래스 class Read2Letter{ private FileReader reader; //멤버변수 reader public Read2Letter(String fileName) { //생성자 try { //인텔리제이의 도움을 받아 try-catch 예외처리 this.reader = new FileReader(fileName); // reader에 FileReader 인스턴스 초기화 } catch (FileNotFoundException e) { //입력된 파일경로에 파일이 존재하지 않는다면 예외 throw new RuntimeException(e); } } public void print2Letter() { for (int i = 0; i < 2; i++) { //2번동안 반복문 실행 try { System.out.println((char)reader.read()); //파일에서 읽어온 글자를 출력 } catch (IOException e) { //입출력 과정에서 발생할 수 있는 다양한 에러들이 있을 때 예외처리 throw new RuntimeException(e); } } } } // Main 클래스 public class Read2LetterMain { public static void main(String[] args) throws IOException { String fileName = "afile.txt"; Read2Letter read2Letter = new Read2Letter(fileName); //Read2Letter 객체 생성 read2Letter.print2Letter();// print2Letter 메소드 호출 } /* 출력결과 h e */ }
Java
복사
두 글자 읽는 코드는 객체지향을 지키며 작성하였다.
FileReader에 "afile.txt"를 전달할 수 있도록 Read2Letter 생성자를 작성하였다. 이때 적절한 예외처리를 할 수 있도록 했다.
Read2Letter에 접근할 수 있는 참조변수 read2Letter를 통해 print2Letter()를 호출하였다.
print2Letter() 메소드는 FileReader 객체를 통해 파일에서 두 글자를 읽어오고 출력한다.

파일에서 N글자 읽기

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; //ReadNLetter 클래스 class ReadNLetter{ private FileReader reader; //멤버변수 reader public ReadNLetter(String filename) { //생성자 try { // 파일이 없는 경우를 대비한 예외처리 this.reader = new FileReader(filename); //객체 생성 시 filename 전달 } catch (FileNotFoundException e) { throw new RuntimeException(e); } } public void printNLetter(int n){ //메소드 호출 시 int n을 받음 for (int i = 0; i < n; i++) { //n번만큼 반복문 순회 try { int strNum = reader.read(); if (strNum != -1){ // -1이 아닌경우, 출력 System.out.println((char) strNum); } else{ System.out.println("모두 출력되었습니다."); break; } } catch (IOException e) { throw new RuntimeException(e); } } } } // Main 클래스 public class ReadNLetterMain { public static void main(String[] args) { String fileName = "afile.txt"; ReadNLetter readNLetter = new ReadNLetter(fileName); readNLetter.printNLetter(15); } /* h e l l o e v e r y o n e */ }
Java
복사
N 글자 읽는 코드는 객체지향을 지키며 작성하였다.
FileReader에 "afile.txt"를 전달할 수 있도록 ReadNLetter 생성자를 작성하였다. 이때 적절한 예외처리를 할 수 있도록 했다.
ReadNLetter에 접근할 수 있는 참조변수 readNLetter를 통해 printNLetter(int num)를 호출하였다.
printNLetter(int num) 메소드는 FileReader 객체를 통해 파일에서 정수 num만큼 읽어오고 출력한다. 이때 int strNum = reader.read() 의 값이 -1인 경우 모든 글자가 출력된 것이므로, if - else 구문을 통해 strNum == -1인 경우 반복문이 끝날 수 있도록 했다.