Springboot에서 File 을 읽어오자
스프링부트에서 자바 코드로 파일을 읽어오기 위해 아래와 같이 코드를 생성했습니다!
Path fileName = Path.of("src/main/resources/template/test.txt");
String actual = Files.readString(fileName);
하지만 Path.of 와 Files.readString에서 인텔리제이가 빨간 밑줄을 쳐줬는데요, 자바8에서는 지원하지 않는 메소드여서 오류가 발생했습니다.
그래서 자바8 기준으로 코드를 수정했습니다.
Path filePath = Paths.get("src/main/resources/template/test.txt");
List<String> lines = Files.readAllLines(filePath);
for (String line : lines) {
System.out.println(line);
}
자바8 기준으로 코드를 수정하니 코드가 길어졌네요. 자바11로 업데이트를 해야겠습니다.
파일을 읽어올 때 파일이 있는 경로인 "src/main/resources/template/test.txt"을 Path에 그대로 적어주었습니다.
하지만 이렇게 파일 패쓰를 적는 것은 패쓰가 변경되었을 경우 오류가 발생할 위험이있다고 합니다.
그래서 ClassPathResource를 사용하는 것을 권장한다고합니다.
ClassPathResource
.java 파일 처럼 컴파일 대상이 되는 소스파일이 아닌 리소스 파일은 리소스 디렉토리에 저장하여 관리합니다.
프로젝트를 빌드하면 리소스 파일들을 CLASS_PATH에 위치하게 됩니다.
스프링 프레임워크에는 이러한 CLASS_PATH에 저장된 리소스 파일을 쉽게 가져올 수 있도록 해주는 ClassPathResource 클래스를 제공합니다.
ClassPathResource를 사용하여 아래와 같이 코드를 수정했습니다.
ClassPathResource resource = new ClassPathResource("template/test.txt");
Path path = Paths.get(resource.getURI());
List<String> lines = Files.readAllLines(filePath);
for (String line : lines) {
System.out.println(line);
}
Path에서는 파일 path 전체를 적어주는 것이 아닌 getURI() 메소드를 사용하여 파일의 경로를 읽어옵니다.
ClassPathResource 는 리소스에 대한 파일 이름, 파일 객체, URL, URI 등 리소스와 관련된 정보를 제공합니다.
resource.getFile(); // 파일 객체
resource.getFilename(); // 파일 이름
resource.getInputStream() // InputStream 객체
resource.getPath(); // 파일 경로
resource.getURL(); // URL 객체
resource.getURI(); // URI 객체
로컬에선 정상인데, 배포하면 파일을 못 읽어요!
그런데 로컬에서 스프링을 띄워 파일 읽는 테스트를 진행했을 때 정상적으로 동작했지만, 알파 환경에 배포 후 테스트를 해보니 정상적으로 파일을 읽어올 수 없었습니다.
왜 그럴까요?
"resource.getFile() expects the resource itself to be available on the file system, i.e. it can't be nested inside a jar file. This is why it works when you run your application in STS but doesn't work once you've built your application and run it from the executable jar. Rather than using getFile() to access the resource's contents, I'd recommend using getInputStream() instead. That'll allow you to read the resource's content regardless of where it's located. " ClassLoader를 통해 resource.getFile()을 사용하여 파일에 접근하게 되면 파일 시스템 자원을 사용할 것으로 기대하지만 jar 또는 war 파일 내부에서는 그렇게 사용 할 수 가 없다. 그래서 STS 에서는 동작하지만 war, jar에서는 동작하지 않는 이유이다. 그래서 getFile()대신 getInputStream()을 사용하면 리소스의 위치에 상관없이 리소스의 콘텐츠를 읽을 수 있다. -출처: https://stackoverflow.com/questions/25869428/classpath-resource-not-found-when-running-as-jar |
배포할 때에는 jar 또는 war 파일로 만들어 실행을하게되는데 jar, war 파일 내부에서는 resource.getFile()를 사용하여 리소스 파일을 읽지 못한다고 합니다.
따라서 아래와 같이 코드를 수정했습니다.
ClassPathResource resource = new ClassPathResource("template/test.txt");
byte[] bdata = FileCopyUtils.copyToByteArray(resource.getInputStream());
String jsonTxt = new String(bdata, StandardCharsets.UTF_8);
getFile() 대신 resource.getInputStream() 을 사용하여 정상동작 하는 것을 확인했습니다.
'스터디 > Spring' 카테고리의 다른 글
[Springboot] CircuitBreaker란 뜻 의미 (0) | 2023.08.17 |
---|---|
[Springboot] @Scheduled cron 사용하는 방법 (0) | 2023.08.12 |
[Spring] 스프링 @MockBean, @SpyBean (0) | 2023.03.12 |
[Spring] 스프링 캐시 알아보기 (@Cacheable, @CachePut, @CacheEvict) (0) | 2023.03.12 |
[Spring] Filter와 Interceptor 의미와 차이 (0) | 2022.10.06 |
댓글