Java

파일 입력 스트림(문자 기반 스트림)

H_u 2024. 5. 31. 11:29
728x90
반응형
SMALL

시나리오 코드 1 Seoul.txt, NewYork.txt 파일 생성하고 내용을 넣어 주세요 기반 스트림 FileReader → 단 인코딩에 대한 단점이 존재한다.

 

package IO.file.ch05;

 

import java.io.BufferedReader;

import java.io.FileReader;

import java.util.Scanner;

 

public class CityInfoApp1 {

 

public static void main(String[] args) {

 

System.out.println("도시 이름을 입력 하세요(예: Seoul, NewYork)");

 

// try catch resource

try(Scanner scanner = new Scanner(System.in)) {

 

String city = scanner.nextLine();

String fileName = city + ".txt";

 

// 1. 파일에 있는 데이터를 응용프로그램으로 가져와야 한다. (문자 기반)

// FileReader (문자 기반 스트림 이다) 단 주의할 사항

// 파일을 읽을 때 시스템의 기본 문자 인코딩을 사용, 운영체제, 지역에 따라 다름

try(FileReader fr = new FileReader(fileName);

BufferedReader br = new BufferedReader(fr)) {

System.out.println(city + " 에 대한 정보 입니다.");

 

String line;

while( ( line = br.readLine() ) != null ) {

System.out.println(line);

}

 

} catch (Exception e) {

System.out.println("해당 파일을 찾을 수 없습니다.");

}

 

} catch (Exception e) {

e.printStackTrace();

}

 

 

} // end of main

 

} // end of class

 

인코딩 설정을 위한 해결 방안 1 - 2

 

package IO.file.ch05;

 

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.Scanner;

 

public class CityInfoApp2 {

 

public static void main(String[] args) {

 

System.out.println("도시 이름을 입력 하세요(예: Seoul, NewYork)");

 

// try catch resource

try(Scanner scanner = new Scanner(System.in)) {

 

String city = scanner.nextLine();

String fileName = city + ".txt";

 

// 1. FileReader 단점 보안 코드

try (FileInputStream fis = new FileInputStream(fileName);

InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

BufferedReader br = new BufferedReader(isr)) {

 

System.out.println(city + " 에 대한 정보 : ");

String line;

while( (line = br.readLine() ) != null ) {

System.out.println(line);

}

 

} catch (Exception e) {

System.out.println("해당 파일을 찾을 수 없습니다");

}

 

 

 

} catch (Exception e) {

e.printStackTrace();

}

 

 

} // end of main

 

} // end of class

 

 

  • 파일 입력 스트림 (FileInputStream): 지정된 파일 이름으로부터 바이트 단위의 입력 스트림을 생성합니다.
  • 문자 입력 스트림 변환기 (InputStreamReader): FileInputStream을 통해 읽은 바이트 데이터를 문자 데이터로 변환합니다. 여기서는 UTF-8 인코딩을 사용합니다.
  • 버퍼링된 문자 입력 스트림 (BufferedReader): InputStreamReader 로부터 데이터를 효율적으로 읽기 위해 버퍼링을 추가합니다. readLine() 메서드를 사용하여 파일의 각 줄을 편리하게 읽을 수 있습니다.

도전 학습 - 가장 많이 사용된 단어 찾기(공백 기준)

파일에는 임의의 긴 문장이 저장되어 있으며 파일 스트림을 활용해서 데이터를 읽고 코드상에서 프로그램을 만들어 보자.

String 클래스의 split 메서드활용 (사전 기반 지식)

Java의 split 메서드는 String 클래스의 메서드로, 문자열을 특정 패턴 또는 정규 표현식을 기준으로 분리하여 문자열 배열(String[])로 반환합니다.

 

public String[] split(String regex)

public String[] split(String regex, int limit)

 

  • regex: 분리할 기준이 되는 정규 표현식입니다.
  • limit: 결과 배열의 크기를 제한할 수 있는 옵션입니다. 이 값을 설정하면 반환되는 배열의 최대 요소 수를 제한할 수 있습니다.

String[] words = line.split("\\s+"); // 공백을 기준으로 분리

String[] words = line.split("[,.\\s]+"); // 쉼표, 마침표, 공백을 구분자로 사용

String[] words = line.split("[^가-힣A-Za-z]+"); // 한글과 영문을 제외한 모든 문자를 구분자로 사용

// "[^가-힣A-Za-z]+"

 

 

^(캐럿)

  • 용도: 입력 문자열의 시작을 나타내는 앵커입니다. 이 메타 문자는 패턴이 문자열의 시작 부분과 일치해야 함을 지정할 때 사용됩니다.
  • 예시:
    • ^abc: "abc"로 시작하는 문자열에만 일치합니다. 예를 들어, "abcdef"는 매치되지만, "defabc"는 매치되지 않습니다.

+ (플러스)

  • 용도: 바로 앞에 있는 요소가 하나 이상 존재할 경우에 일치합니다. 즉, 앞의 표현이 최소 한 번 이상 반복되어야 할 때 사용합니다.
  • 예시:
    • a+: 'a'가 하나 이상 있는 모든 시퀀스에 일치합니다. "a", "aa", "aaa" 등이 이에 해당합니다.

 

💡 ^[a-z]+: 이 정규 표현식은 소문자 알파벳으로 시작하고, 하나 이상의 소문자가 연속해서 나타나는 문자열에 매치됩니다.

단, 대괄호 안에서 캐럿을 사용하면 "부정 문자 클래스"를 의미합니다.

 

[ … ] 대괄호의 주요 의미와 사용

  1. 문자 집합:
    • 대괄호 안에 나열된 문자들 중 하나와 매치됩니다.
    • 예: **[abc]**는 a, b, 또는 c 중 하나와 매치됩니다.
  2. 문자 범위:
    • 대괄호 안에 하이픈(-)**``**을 사용하여 범위를 지정할 수 있습니다.
    • 예: **[a-z]**는 소문자 알파벳 **a**에서 **z**까지의 모든 문자와 매치됩니다.
    • 예: **[A-Z]**는 대문자 알파벳 **A**에서 **Z**까지의 모든 문자와 매치됩니다.
    • 예: **[0-9]**는 숫자 **0**에서 **9**까지의 모든 문자와 매치됩니다.
  3. 부정 (not):
    • 대괄호 안의 첫 번째 문자로 **^**를 사용하여 부정을 나타낼 수 있습니다. 이는 대괄호 안에 나열된 문자들을 제외한 모든 문자와 매치됨을 의미합니다.
    • 예: **[^abc]**는 a, b, **c**를 제외한 모든 문자와 매치됩니다.

[^가-힣A-Za-z]+의 의미:

  • 가-힣: 한글 문자 범위 (가에서 힣까지 모든 한글 문자)
  • A-Za-z: 모든 영문 대소문자
  • [^가-힣A-Za-z]: 한글 문자와 영문 대소문자를 제외한 모든 문자
  • +: 한 번 이상 반복

문자열 "안녕하세요! Hello123" 에서 [^가-힣A-Za-z]+ 패턴을 적용하면, "! "와 "123" 이 매치됩니다.

 

package IO.file.ch05;

 

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.util.HashMap;

import java.util.Map;

 

public class WordFinder {

 

public static void main(String[] args) {

 

String fileName = "Seoul.txt";

 

try (FileInputStream fis = new FileInputStream(fileName);

InputStreamReader isr = new InputStreamReader(fis);

BufferedReader br = new BufferedReader(isr)) {

 

// 단어 빈도를 저장하기 위한 HashMap 생성

Map<String, Integer> wordCountMap = new HashMap<>();

String line;

while ((line = br.readLine()) != null) {

String[] words = line.split("\\s+");

 

// 분리된 단어들을 반복 처리

for (String word : words) {

// System.out.println("word : " + word);

// 빈 문자열이 아닐 경우에만 처리

if (!word.isEmpty()) {

// getOrDefault - 분리한 word 단어가 이미 map 구조에 존재한다면 현재

// 값을 가져오고 없다면 0을 반환 합니다.

// wordCountMap key - String

// wordCountMap value - Integer

wordCountMap.put(word, wordCountMap.getOrDefault(word, 0) + 1);

}

}

} // end of while

 

String mostCommon = null;

int maxCount = 0;

 

for (Map.Entry<String, Integer> entry : wordCountMap.entrySet()) {

if (entry.getValue() > maxCount) {

mostCommon = entry.getKey();

maxCount = entry.getValue();

}

}

System.out.println("가장 많이 사용된 단어 : " + mostCommon + " , " + maxCount + "회");

} catch (Exception e) {

e.printStackTrace();

}

 

} // end of main

 

} // end of class

728x90
반응형
SMALL