자바 테스트 파일 읽는 방법

1. 개요

이 튜토리얼에서는 File in Java에서 읽는 다양한 방법을 살펴 봅니다 .

먼저 클래스 경로, URL 또는 표준 Java 클래스를 사용하여 JAR 파일에서 파일을로드하는 방법을 배웁니다.

둘째, BufferedReader , Scanner , StreamTokenizer , DataInputStream , SequenceInputStreamFileChannel을 사용 하여 콘텐츠를 읽는 방법을 살펴 보겠습니다  . 또한 UTF-8 인코딩 파일을 읽는 방법에 대해서도 설명합니다.

마지막으로 Java 7 및 Java 8에서 파일을로드하고 읽는 새로운 기술을 살펴 보겠습니다.

이 기사는  Baeldung 에 대한 "Java – Back to Basic"시리즈의 일부입니다.

2. 설정

2.1 입력 파일

이 기사의 대부분의 예제에서는 한 줄이 포함 된 fileTest.txt 파일 이름의 텍스트 파일을 읽습니다 .

Hello, world!

몇 가지 예를 들어 다른 파일을 사용합니다. 이 경우 파일과 그 내용을 명시 적으로 언급합니다.

2.2 도우미 방법

핵심 Java 클래스에만 테스트 예제 세트를 사용하고 테스트에서는 Hamcrest 매처 와 함께 어설 션을 사용 합니다.

테스트는 결과를보다 쉽게 ​​주장 할 수 있도록 InputStreamString으로 변환하는 일반적인 readFromInputStream 메서드를 공유합니다 .

private String readFromInputStream(InputStream inputStream)
  throws IOException {
    StringBuilder resultStringBuilder = new StringBuilder();
    try (BufferedReader br
      = new BufferedReader(new InputStreamReader(inputStream))) {
        String line;
        while ((line = br.readLine()) != null) {
            resultStringBuilder.append(line).append("\n");
        }
    }
  return resultStringBuilder.toString();
}

이와 동일한 결과를 얻는 다른 방법이 있습니다. 이 문서 에서 몇 가지 대안을 참조 할 수 있습니다 .

3. 클래스 경로에서 파일 읽기

3.1. 표준 자바 사용

이 섹션에서는 클래스 경로에서 사용 가능한 파일을 읽는 방법을 설명합니다. src / main / resources 아래에 있는 " fileTest.txt "를 읽을 것입니다 .

@Test
public void givenFileNameAsAbsolutePath_whenUsingClasspath_thenFileData() {
    String expectedData = "Hello, world!";
    
    Class clazz = FileOperationsTest.class;
    InputStream inputStream = clazz.getResourceAsStream("/fileTest.txt");
    String data = readFromInputStream(inputStream);

    Assert.assertThat(data, containsString(expectedData));
}

위의 코드 스 니펫에서 현재 클래스를 사용하여 getResourceAsStream 메소드를 사용하여 파일을로드하고로드 할 파일 의 절대 경로를 전달했습니다.

ClassLoader 인스턴스에서도 동일한 메서드를 사용할 수 있습니다.

ClassLoader classLoader = getClass().getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("fileTest.txt");
String data = readFromInputStream(inputStream);

getClass (). getClassLoader ()를 사용하여 현재 클래스 classLoader얻습니다 .

주요 차이점은 ClassLoader 인스턴스 에서 getResourceAsStream사용할 때 경로가 클래스 경로의 루트에서 시작하는 절대 경로로 처리 된다는 것 입니다.

대해 사용될 때, 클래스 인스턴스 , 경로는 슬래시 의해 암시되는 패키지 또는 절대 경로에 상대적 일 수있다.

물론, 실제로 는 우리 예제 InputStream 과 같이 열린 스트림은 항상 닫혀 있어야합니다 .

InputStream inputStream = null;
try {
    File file = new File(classLoader.getResource("fileTest.txt").getFile());
    inputStream = new FileInputStream(file);
    
    //...
}     
finally {
    if (inputStream != null) {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3.2. 은 Using 공유지를-IO 라이브러리

또 다른 일반적인 옵션은 commons-io 패키지 FileUtils 클래스를 사용하는 것입니다 .

@Test
public void givenFileName_whenUsingFileUtils_thenFileData() {
    String expectedData = "Hello, world!";
        
    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource("fileTest.txt").getFile());
    String data = FileUtils.readFileToString(file, "UTF-8");
        
    assertEquals(expectedData, data.trim());
}

여기서는 File 객체를 FileUtils 클래스 readFileToString () 메소드에 전달합니다 . 이 유틸리티 클래스는 InputStream 인스턴스 를 생성하고 데이터를 읽기 위해 상용구 코드를 작성할 필요없이 콘텐츠를로드하도록 관리합니다 .

동일한 라이브러리는 IOUtils  클래스 도 제공합니다 .

@Test
public void givenFileName_whenUsingIOUtils_thenFileData() {
    String expectedData = "Hello, world!";
        
    FileInputStream fis = new FileInputStream("src/test/resources/fileTest.txt");
    String data = IOUtils.toString(fis, "UTF-8");
        
    assertEquals(expectedData, data.trim());
}

여기에서 FileInputStream 객체를 IOUtils 클래스 toString () 메서드에 전달합니다 . 이 유틸리티 클래스는 InputStream 인스턴스 를 생성하고 데이터를 읽기 위해 이전 클래스와 동일한 방식으로 작동 합니다.

4. BufferedReader로 읽기

이제 파일 내용을 구문 분석하는 다양한 방법에 초점을 맞 춥니 다.

BufferedReader를 사용하여 파일에서 읽는 간단한 방법으로 시작합니다 .

@Test
public void whenReadWithBufferedReader_thenCorrect()
  throws IOException {
     String expected_value = "Hello, world!";
     String file ="src/test/resources/fileTest.txt";
     
     BufferedReader reader = new BufferedReader(new FileReader(file));
     String currentLine = reader.readLine();
     reader.close();

    assertEquals(expected_value, currentLine);
}

참고 내의 readLine ()가 반환 널 (null)를 파일의 끝에 도달했을 때.

5. Java NIO를 사용하여 파일에서 읽기

JDK7에서는 NIO 패키지가 크게 업데이트되었습니다.

Files 클래스와 readAllLines  메서드 를 사용하는 예제를 살펴 보겠습니다 . readAllLines의  방법은 받아 경로.

경로 클래스는 몇 가지 추가 작업 이있는 java.io.File 의 업그레이드로 간주 될 수 있습니다 .

5.1. 작은 파일 읽기

다음 코드는 새 Files 클래스를 사용하여 작은 파일을 읽는 방법을 보여줍니다 .

@Test
public void whenReadSmallFileJava7_thenCorrect()
  throws IOException {
    String expected_value = "Hello, world!";

    Path path = Paths.get("src/test/resources/fileTest.txt");

    String read = Files.readAllLines(path).get(0);
    assertEquals(expected_value, read);
}

바이너리 데이터가 필요한 경우에도 readAllBytes () 메서드를 사용할 수 있습니다 .

5.2. 큰 파일 읽기

Files 클래스 로 큰 파일을 읽으려면 BufferedReader를 사용할 수 있습니다 .

다음 코드는 새 Files 클래스와 BufferedReader를 사용하여 파일을 읽습니다 .

@Test
public void whenReadLargeFileJava7_thenCorrect()
  throws IOException {
    String expected_value = "Hello, world!";

    Path path = Paths.get("src/test/resources/fileTest.txt");

    BufferedReader reader = Files.newBufferedReader(path);
    String line = reader.readLine();
    assertEquals(expected_value, line);
}

5.3. Files.lines ()를 사용하여 파일 읽기

JDK8은 Files 클래스 내부에 lines () 메서드를 제공합니다 . Stream of String 요소를 반환합니다 .

데이터를 바이트로 읽고 UTF-8 문자 세트를 사용하여 디코딩하는 방법의 예를 살펴 보겠습니다.

다음 코드는 new Files.lines ()를 사용하여 파일을 읽습니다 .

@Test
public void givenFilePath_whenUsingFilesLines_thenFileData() {
    String expectedData = "Hello, world!";
         
    Path path = Paths.get(getClass().getClassLoader()
      .getResource("fileTest.txt").toURI());
         
    Stream<String> lines = Files.lines(path);
    String data = lines.collect(Collectors.joining("\n"));
    lines.close();
         
    Assert.assertEquals(expectedData, data.trim());
}

파일 작업과 같은 IO 채널과 함께 Stream을 사용하려면 close () 메서드를 사용하여 명시 적으로 스트림을 닫아야합니다  .

보시다시피 Files API는 파일 내용을 문자열 로 읽는 또 다른 쉬운 방법을 제공합니다 .

다음 섹션에서는 일부 상황에서 적절할 수있는 덜 일반적인 파일 읽기 방법을 살펴 보겠습니다.

6. 스캐너로 읽기

다음으로 스캐너사용 하여 파일에서 읽어 보겠습니다 . 여기서는 구분자로 공백을 사용합니다.

@Test
public void whenReadWithScanner_thenCorrect()
  throws IOException {
    String file = "src/test/resources/fileTest.txt";
    Scanner scanner = new Scanner(new File(file));
    scanner.useDelimiter(" ");

    assertTrue(scanner.hasNext());
    assertEquals("Hello,", scanner.next());
    assertEquals("world!", scanner.next());

    scanner.close();
}

기본 구분 기호는 공백이지만 Scanner에서 여러 구분 기호를 사용할 수 있습니다 .

스캐너 콘솔에서 콘텐츠를 판독하거나, 콘텐츠 프리미티브 값을 포함하는 경우 클래스 때 유용하다 (: 정수의리스트가 공백으로 분리 등)를 공지 된 구분자를.

7. StreamTokenizer로 읽기

이제 StreamTokenizer를 사용하여 텍스트 파일을 토큰으로 읽어 보겠습니다 .

토크 나이 저는 먼저 다음 토큰이 문자열 또는 숫자인지 파악하여 작동합니다. tokenizer.ttype  필드 를 살펴보면됩니다 .

그런 다음이 유형을 기반으로 실제 토큰을 읽습니다.

  • tokenizer.nval – 유형이 숫자 인 경우
  • tokenizer.sval – 유형이 문자열 인 경우

이 예제에서는 단순히 다음을 포함하는 다른 입력 파일을 사용합니다.

Hello 1

다음 코드는 파일에서 문자열과 숫자를 읽습니다.

@Test
public void whenReadWithStreamTokenizer_thenCorrectTokens()
  throws IOException {
    String file = "src/test/resources/fileTestTokenizer.txt";
   FileReader reader = new FileReader(file);
    StreamTokenizer tokenizer = new StreamTokenizer(reader);

    // token 1
    tokenizer.nextToken();
    assertEquals(StreamTokenizer.TT_WORD, tokenizer.ttype);
    assertEquals("Hello", tokenizer.sval);

    // token 2    
    tokenizer.nextToken();
    assertEquals(StreamTokenizer.TT_NUMBER, tokenizer.ttype);
    assertEquals(1, tokenizer.nval, 0.0000001);

    // token 3
    tokenizer.nextToken();
    assertEquals(StreamTokenizer.TT_EOF, tokenizer.ttype);
    reader.close();
}

마지막에 파일 토큰의 끝이 어떻게 사용되는지 확인하십시오.

이 접근 방식은 입력 스트림을 토큰으로 구문 분석하는 데 유용합니다.

8. DataInputStream으로 읽기

DataInputStream사용 하여 파일에서 이진 또는 원시 데이터 유형을 읽을 수 있습니다 .

다음 테스트는 DataInputStream을 사용하여 파일을 읽습니다 .

@Test
public void whenReadWithDataInputStream_thenCorrect() throws IOException {
    String expectedValue = "Hello, world!";
    String file ="src/test/resources/fileTest.txt";
    String result = null;

    DataInputStream reader = new DataInputStream(new FileInputStream(file));
    int nBytesToRead = reader.available();
    if(nBytesToRead > 0) {
        byte[] bytes = new byte[nBytesToRead];
        reader.read(bytes);
        result = new String(bytes);
    }

    assertEquals(expectedValue, result);
}

9. FileChannel로 읽기

대용량 파일을 읽는 경우 FileChannel 이 표준 IO보다 빠를 수 있습니다.

다음 코드는 FileChannelRandomAccessFile을 사용하여 파일에서 데이터 바이트를 읽습니다 .

@Test
public void whenReadWithFileChannel_thenCorrect()
  throws IOException {
    String expected_value = "Hello, world!";
    String file = "src/test/resources/fileTest.txt";
    RandomAccessFile reader = new RandomAccessFile(file, "r");
    FileChannel channel = reader.getChannel();

    int bufferSize = 1024;
    if (bufferSize > channel.size()) {
        bufferSize = (int) channel.size();
    }
    ByteBuffer buff = ByteBuffer.allocate(bufferSize);
    channel.read(buff);
    buff.flip();
    
    assertEquals(expected_value, new String(buff.array()));
    channel.close();
    reader.close();
}

10. UTF-8 인코딩 파일 읽기

이제 BufferedReader를 사용하여 UTF-8로 인코딩 된 파일을 읽는 방법을 살펴 보겠습니다 . 이 예에서는 중국어 문자가 포함 된 파일을 읽습니다.

@Test
public void whenReadUTFEncodedFile_thenCorrect()
  throws IOException {
    String expected_value = "青空";
    String file = "src/test/resources/fileTestUtf8.txt";
    BufferedReader reader = new BufferedReader
      (new InputStreamReader(new FileInputStream(file), "UTF-8"));
    String currentLine = reader.readLine();
    reader.close();

    assertEquals(expected_value, currentLine);
}

11. URL에서 콘텐츠 읽기

URL에서 콘텐츠를 읽으려면 다음 예에서 " / "URL을 사용합니다 .

@Test
public void givenURLName_whenUsingURL_thenFileData() {
    String expectedData = "Baeldung";

    URL urlObject = new URL("/");
    URLConnection urlConnection = urlObject.openConnection();
    InputStream inputStream = urlConnection.getInputStream();
    String data = readFromInputStream(inputStream);

    Assert.assertThat(data, containsString(expectedData));
}

URL에 연결하는 다른 방법도 있습니다. 여기서는 표준 SDK에서 사용할 수 있는 URLURLConnection 클래스를 사용했습니다.

12. JAR에서 파일 읽기

JAR 파일 안에있는 파일을 읽으려면 그 안에 파일이있는 JAR이 필요합니다. 이 예 에서는“ hamcrest-library-1.3.jar ”파일 에서 LICENSE.txt ”를 읽습니다 .

@Test
public void givenFileName_whenUsingJarFile_thenFileData() {
    String expectedData = "BSD License";

    Class clazz = Matchers.class;
    InputStream inputStream = clazz.getResourceAsStream("/LICENSE.txt");
    String data = readFromInputStream(inputStream);

    Assert.assertThat(data, containsString(expectedData));
}

여기 에서 Hamcrest 라이브러리에있는 LICENSE.txt 를로드하려고 하므로 리소스를 얻는 데 도움이 되는 Matcher의 클래스를 사용합니다 . 클래스 로더를 사용하여 동일한 파일을로드 할 수도 있습니다.

13. 결론

보시다시피 일반 Java를 사용하여 파일을로드하고 데이터를 읽을 수있는 많은 가능성이 있습니다.

클래스 경로, URL 또는 jar 파일과 같은 다양한 위치에서 파일을로드 할 수 있습니다.

그런 다음 BufferedReader사용 하여 한 줄씩 읽고 스캐너 를 사용하여 다른 구분 기호 를 읽고 StreamTokenizer사용하여 파일을 토큰 으로 읽고 DataInputStream 을 사용하여 이진 데이터 및 기본 데이터 유형을 읽고 SequenceInput Stream 을 사용하여 여러 파일을 하나의 스트림으로 연결하고 FileChannel 을 사용하여 더 빠르게 읽을 수 있습니다. 대용량 파일 등에서

다음 GitHub 저장소 에서이 기사의 소스 코드를 찾을 수 있습니다 .