본문 바로가기
Java/자바 Stream

[Java] 85. 파일 입력 스트림(1) (문자 기반 스트림)

글: Song hyun 2024. 5. 20.
728x90
반응형

[Java] 85. 파일 입력 스트림(1) (문자 기반 스트림)

1. 시나리오 코드(1)

2. 시나리오 코드(2)

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


1. 시나리오 코드(1)

-파일 입력 스트림(FileInputStream)

-문자 입력 스트림 변환기(InputStreamReader)

-버퍼링된 문자 입력 스트림(BufferedReader)

package io.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 and 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

 

 

2. 시나리오 코드(2)

-파일 기반 입력 스트림에는 단점 역시 존재한다.

package io.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 and 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

 

 

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

-Split 메서드: string 클래스의 메서드로, 문자열을 특정 패턴 혹은 분리하여 string[]로 반환한다.

 

(1) ^(캐롯):

-용도:

-예시:

 

(2) +(플러스)

-용도

-예시

 

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

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.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();
		}

	}
}
728x90
반응형