** ๐ PART 5.1 ํ์ผ ์ ๋ก๋์ ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ์ ์ต์ ํ ์ ๋ต **
โํ์ผ์ ์ฌ๋ฆด ๋ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํฐ์ง์ง ์๋๋ก ์์ ํ๊ฒ ์ฒ๋ฆฌํ๋ ๋ฒโ
๐ข 1๋จ๊ณ. ํ์ผ ์ ๋ก๋๊ฐ ๋ญ์ผ?
๐ฌ ์ฌ์ฉ์๊ฐ ๋ด ์ปดํจํฐ์ ์๋ ์ฌ์ง์ด๋ ๋ฌธ์๋ฅผ
์น ์ฌ์ดํธ์ ์ฒจ๋ถํด์ ์๋ฒ๋ก ๋ณด๋ด๋ ๊ธฐ๋ฅ์ด์ผ.
<form method="POST" enctype="multipart/form-data">
<input type="file" name="photo" />
<input type="submit" value="์
๋ก๋" />
</form>
โ ์ด๊ฑธ ์๋ฒ๊ฐ ๋ฐ์ผ๋ ค๋ฉด?
- ์ผ๋ฐ
request.getParameter()
๋ก๋ ํ์ผ์ ๋ฐ์ ์ ์์ โ -
๋์ ํ์ผ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ ํน๋ณํ ์์ฒญ์ธ
"multipart/form-data"
๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด์ผ ํด!โ ์ด๊ฒ์ Multipart ์์ฒญ ์ฒ๋ฆฌ๋ผ๊ณ ํด์.
๐ฆ 2๋จ๊ณ. MultipartRequest๋? (cos.jar or commons-fileupload)
โ cos.jar ์ฌ์ฉ ์์ (๊ฐ์ฅ ์ฌ์)
MultipartRequest multi = new MultipartRequest(
request,
"C:/upload/", // ์
๋ก๋ ๊ฒฝ๋ก
10 * 1024 * 1024, // ์ต๋ ์
๋ก๋ ์ฉ๋ (10MB)
"UTF-8"
);
โ ์ฒ๋ฆฌ ํ๋ฆ
1. ํ์ผ ์
๋ก๋ ์์ฒญ์ด ๋ค์ด์ด
2. MultipartRequest๊ฐ ์์ฒญ์ ํ์ฑํจ
3. ํ์ผ์ ์๋ฒ ํ๋๋์คํฌ(๊ฒฝ๋ก)์ ์ ์ฅ๋จ
4. ์ผ๋ฐ ํ
์คํธ๋ ๋ฉ๋ชจ๋ฆฌ์์ ์ฒ๋ฆฌ๋จ
๐พ 3๋จ๊ณ. ์์ ํ์ผ ์ ์ฅ vs ๋ฉ๋ชจ๋ฆฌ ์ ์ฅ ์ฐจ์ด์
๊ตฌ๋ถ | ์ค๋ช | ๋ฉ๋ชจ๋ฆฌ ์ํฅ |
---|---|---|
์์ ํ์ผ ์ ์ฅ | ํ์ผ ๋ด์ฉ์ ์๋ฒ์ ํ๋๋์คํฌ์ ์ ์ฅ | ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ ์ โ |
๋ฉ๋ชจ๋ฆฌ ์ ์ฅ | ์์ ํ์ผ(text, ํ๋ ๊ฐ ๋ฑ)์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ | ๋๋ฌด ๋ง์ผ๋ฉด GC/๋ฉ๋ชจ๋ฆฌ ํฐ์ง ์ํ โ |
โ ์ ๋ก๋ํ ๋ ํ์ผ์ด ์ด๋์ ์ ์ฅ๋ ๊น?
- ํ
์คํธ ๋ฐ์ดํฐ (์: name=ํ๊ธธ๋) โ
request
๋ฉ๋ชจ๋ฆฌ ๋ด๋ถ - ํ์ผ (์: photo.jpg) โ ์ง์ ํ ๊ฒฝ๋ก ํ๋๋์คํฌ
๐ฅ ๋ฌธ์ : ํฐ ํ์ผ์ ๊ณ์ ์ฌ๋ฆฌ๋ฉด?
์๋ฒ๋ ์์ฒญ์ ํ์ฑํ๊ธฐ ์ ์ ์ ์ฒด ์์ฒญ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฝ๊ฒ ๋๋๋ฐ,
ํ์ผ์ด ๋๋ฌด ํฌ๊ฑฐ๋ ๋์์ ๋๋ฌด ๋ง์ด ์ฌ๋ผ์ค๋ฉด โ ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ค๋ฅ ๋ฐ์!
๐ฑ ์ค๋ฅ ์์: java.lang.OutOfMemoryError: Java heap space
๐ง 4๋จ๊ณ. ํฐ ํ์ผ ์ ๋ก๋ ์ ๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ ๋ฐฉ์ง ์ ๋ต
โ ์ ๋ต 1: ์ ๋ก๋ ํฌ๊ธฐ ์ ํ ์ค์
// ์ต๋ 10MB๊น์ง ์
๋ก๋ ๊ฐ๋ฅ
MultipartRequest multi = new MultipartRequest(
request,
"C:/upload/",
10 * 1024 * 1024, // 10MB
"UTF-8"
);
โ ๋๋ฌด ํฐ ํ์ผ์ ๊ฑฐ๋ถํด์ ์๋ฒ๋ฅผ ์งํด!
โ ์ ๋ต 2: ์ ๋ก๋ ๊ฒฝ๋ก๋ฅผ ์ธ๋ถ ๋์คํฌ๋ก ๋ถ๋ฆฌ
-
์ ๋ก๋๋ ํ์ผ์
C:/upload/
๊ฐ์ ํ๋๋์คํฌ์ ์ ์ฅ๋๋ฏ๋กโ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ ๋์คํฌ ๊ณต๊ฐ ์ฌ์ฉ์ผ๋ก GC ๋ถ๋ด โ
โ ์ ๋ต 3: commons-fileupload ์ฌ์ฉ + ์คํธ๋ฆฌ๋ฐ ์ ๋ก๋ ๋ฐฉ์
Apache commons-fileupload๋ ์์ฒญ์ ํ ์ค์ฉ ์ฝ์ผ๋ฉด์ ์ฒ๋ฆฌํ ์ ์์
โ ์ ์ฒด ํ์ผ์ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆฌ์ง ์์๋ ๋จ!
โ Streaming ๋ฐฉ์ ์์ ํ๋ฆ (์ค์)
1. ์์ฒญ์ด ๋ค์ด์ค๋ฉด โ InputStream์ผ๋ก ํ ์ค์ฉ ์ฝ๊ธฐ
2. ๋ฉ๋ชจ๋ฆฌ์ ์์ง ์๊ณ โ ๋ฐ๋ก ํ๋๋์คํฌ์ ์ฐ๊ธฐ
3. ์ฉ๋ ์๊ด์์ด ์์ ์ ์ผ๋ก ์
๋ก๋ ๊ฐ๋ฅ!
โ ์ ๋ต 4: Tomcat์ ์ ๋ก๋ ์ค์ ์ ํํ๊ธฐ (web.xml or server.xml)
<!-- web.xml -->
<multipart-config>
<max-file-size>10485760</max-file-size> <!-- 10MB -->
<max-request-size>20971520</max-request-size> <!-- 20MB -->
</multipart-config>
โ ์๋ฒ ์ฐจ์์์๋ ๋ฐฉ์ด!
๐ 5๋จ๊ณ. ๋ฉด์ ํฌ์ธํธ ์ ๋ฆฌ
์ง๋ฌธ | ๋ชจ๋ฒ ๋ต๋ณ ์์ฝ |
---|---|
MultipartRequest๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์? | ํ ์คํธ๋ ๋ฉ๋ชจ๋ฆฌ์, ํ์ผ์ ๋์คํฌ์ ์ ์ฅํฉ๋๋ค |
ํฐ ํ์ผ ์ ๋ก๋ ์ ์ OOM์ด ๋ฐ์ํ๋์? | ๋ฉ๋ชจ๋ฆฌ๋ก ์ ์ฒด ์์ฒญ์ ์ฝ์ผ๋ ค๋ค ์ฉ๋ ์ด๊ณผ |
๋ฉ๋ชจ๋ฆฌ ํญ๋ฐ ๋ฐฉ์ง ์ ๋ต์? | ํฌ๊ธฐ ์ ํ + ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ + ๋์คํฌ ์ ์ฅ ๊ฒฝ๋ก ๋ถ๋ฆฌ |
cos.jar vs commons-fileupload ์ฐจ์ด๋? | cos๋ ๊ฐ๋จ, commons๋ ์ฑ๋ฅ/ํ์ฅ์ฑ ์ฐ์ |
์ ๋ก๋ ์ฉ๋ ์ค์ ์ ์ด๋์ ํ๋์? | MultipartRequest ์ฝ๋, web.xml, ๋๋ Tomcat ์ค์ ์์ |
โ ๋ง๋ฌด๋ฆฌ ์์ฝํ
ํญ๋ชฉ | ์ค๋ช | ๋ฉ๋ชจ๋ฆฌ ํจ๊ณผ |
---|---|---|
MultipartRequest | ์์ฒญ์ ํ์ฑํ๊ณ ํ์ผ ์ ์ฅ | ํฐ ํ์ผ์ ๋์คํฌ๋ก ์ฒ๋ฆฌ |
ํ ์คํธ ํ๋ | ๋ฉ๋ชจ๋ฆฌ ์ ์ฅ | ๋ค๋ ์์ฒญ ์ GC ๋ถ๋ด โ |
์ ๋ก๋ ์ ํ | max size ์ค์ | OOM ๋ฐฉ์ง, ์ฑ๋ฅ ์์ |
์คํธ๋ฆฌ๋ฐ ์ ๋ก๋ | InputStream ์ฒ๋ฆฌ | ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ๊ฑฐ์ ์์ โ |
โ PART 5.2 ๋ค์ด๋ก๋ ์ ํ์ผ ์คํธ๋ฆผ ๋ฒํผ๋ง ์ ๋ต
โํ์ผ์ ๋น ๋ฅด๊ณ ์์ ํ๊ฒ ์ ์กํ๋ฉด์ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ๋ ๋ณดํธํ๋ ๋ฒโ
๐ข 1๋จ๊ณ. ํ์ผ ๋ค์ด๋ก๋ ๊ตฌ์กฐ๋ถํฐ ์ดํดํ์
๐ฌ ํ์ผ ๋ค์ด๋ก๋๋, ์๋ฒ์ ์ ์ฅ๋ ํ์ผ์
๋ธ๋ผ์ฐ์ ์ ์ ์กํด์ ์ฌ์ฉ์๊ฐ ๋ฐ์ ์ ์๋๋ก ํ๋ ๊ธฐ๋ฅ์ด์ผ.
โ ํ๋ฆ ์์ฝ
1. ์ฌ์ฉ์๊ฐ ๋ค์ด๋ก๋ ๋ฒํผ ํด๋ฆญ
2. ์๋ฒ๊ฐ ํ์ผ์ ์ฝ์ (InputStream)
3. ์ฌ์ฉ์์๊ฒ ์ ์กํจ (OutputStream)
๐ฆ JSP/Servlet ๋ค์ด๋ก๋ ๊ธฐ๋ณธ ์ฝ๋ ์์
File file = new File("C:/upload/sample.pdf");
FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
๐ 2๋จ๊ณ. Stream ์ง์ ์ฒ๋ฆฌ vs ByteBuffer ์ฐจ์ด์
โ ๋ฐฉ์ 1: Stream ์ง์ ์ฒ๋ฆฌ (์ ์ฝ๋์ฒ๋ผ)
InputStream
์ผ๋ก ์ฝ๊ณ ,OutputStream
์ผ๋ก ๋ฐ๋ก ์byte[] buffer
๋ฅผ ๋ง๋ค์ด์ ๋ฐ์ดํฐ๋ฅผ ์กฐ๊ฐ์กฐ๊ฐ ์ ๋ฌํจ
์ฅ์
- ๋ฉ๋ชจ๋ฆฌ ์ ๊ฒ ์ (๋ฒํผ๋ก ๋๋ ์ ์ ์ก)
- ๊ฐ๋จํ ๊ตฌ์กฐ, ๋๋ถ๋ถ ์ด ๋ฐฉ์ ์ฌ์ฉ
โ ๋ฐฉ์ 2: ByteBuffer ์ฌ์ฉ (NIO ๊ธฐ๋ฐ ๊ณ ์ฑ๋ฅ ๋ฐฉ์)
Path path = Paths.get("C:/upload/sample.pdf");
ByteBuffer buffer = ByteBuffer.allocate(8192); // 8KB
try (SeekableByteChannel channel = Files.newByteChannel(path)) {
while (channel.read(buffer) > 0) {
buffer.flip();
out.write(buffer.array(), 0, buffer.limit());
buffer.clear();
}
}
์ฅ์
- NIO(Non-blocking IO) ๊ธฐ๋ฐ โ ์ฑ๋ฅ ์ฐ์
- ๋์ฉ๋ ์ฒ๋ฆฌ์ ๊ฐํจ
- GC ํจ์จ์ (DirectBuffer ์ฌ์ฉ ๊ฐ๋ฅ)
โ ์ฑ๋ฅ/๋ฉ๋ชจ๋ฆฌ ๋น๊ต ์์ฝํ
ํญ๋ชฉ | Stream ๋ฐฉ์ | ByteBuffer(NIO) ๋ฐฉ์ |
---|---|---|
์๋ | ์ค๊ฐ | ๋น ๋ฆ (NIO ์ต์ ํ) |
์ฝ๋ ๊ฐ๋จ์ฑ | ๐ ๋งค์ฐ ์ฌ์ | ์ค์ ๋ณต์ก |
๋ฉ๋ชจ๋ฆฌ ํจ์จ | ๋ณดํต (heap ์ฌ์ฉ) | ๋์ (heap ๋ฐ์์ ์ฒ๋ฆฌ ๊ฐ๋ฅ) |
์ค๋ฌด ์ฌ์ฉ | ์ผ๋ฐ ์น์์๋ Stream | ๋์ฉ๋/๊ณ ์ฑ๋ฅ ์์คํ ์์ NIO ์ฌ์ฉ |
๐พ 3๋จ๊ณ. flush() / close()์ ์ญํ ๊ณผ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง ์ ๋ต
โ flush()
๐ฌ ๋ฒํผ์ ์์ธ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ๋ด๋ณด๋ด๋ ์ญํ
write()
๋ง ํ๋ฉด ์ค์ ์ ์ก ์ ๋ ์ ์์flush()
๋ฅผ ํด์ค์ผ โ ๋คํธ์ํฌ๋ก ์ ์ก๋จ!
out.flush(); // ๐ก ์ด๊ฑฐ ๊ผญ ํด์ค์ผ ํด๋ผ์ด์ธํธ๊ฐ ํ์ผ์ ์์ ํ ๋ฐ์!
โ close()
๐ฌ ํ์ผ ์คํธ๋ฆผ์ ์์ ํ ๋ซ๊ณ , ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๋ฉ์๋
- ์ ํ๋ฉด โ ์คํธ๋ฆผ์ด ๊ณ์ ์ด์์์ด์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ์
- ํนํ ํ์ผ ์คํธ๋ฆผ์ OS ์์์ ์ ์ ํจ!
in.close();
out.close();
๐ง ์ค๋ฌด ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง ํต์ฌ ์ ๋ต
์ ๋ต | ์ค๋ช |
---|---|
try-with-resources ์ฌ์ฉ | ์๋์ผ๋ก close() ํธ์ถ๋จ |
flush() โ close() ์์ ์งํค๊ธฐ | ์ ํ๋ฉด ํ์ผ ์ผ๋ถ ๋๋ฝ ๊ฐ๋ฅ |
๋์ฉ๋์ ๋ฐ๋์ buffer ์ฌ์ฉ | ๋ฒํผ ์์ด ์ฒ๋ฆฌ ์ ๋ฉ๋ชจ๋ฆฌ ํญ์ฃผ ๊ฐ๋ฅ |
๋ก๊ทธ ์ถ๋ ฅ ์ ํ | ๋ค์ด๋ก๋ ์ค ๋๋ฌด ๋ง์ ๋ก๊ทธ ์ถ๋ ฅ์ GC ์๋ฐ ๋ฐ์ |
โ try-with-resources ์ฌ์ฉ ์์ (์ถ์ฒ ๋ฐฉ์)
try (
FileInputStream in = new FileInputStream(file);
OutputStream out = response.getOutputStream();
) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
โ ์๋์ผ๋ก close()
ํธ์ถ๋จ โ ๋ฉ๋ชจ๋ฆฌ ์์ โ
๐ 4๋จ๊ณ. ๋ฉด์ ํฌ์ธํธ ์ ๋ฆฌ
์ง๋ฌธ | ๋ชจ๋ฒ ๋ต๋ณ ์์ฝ |
---|---|
ํ์ผ ๋ค์ด๋ก๋๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์? | InputStream์ผ๋ก ์ฝ๊ณ , OutputStream์ผ๋ก ํด๋ผ์ด์ธํธ์ ์ ์กํฉ๋๋ค |
ByteBuffer๋ ์ธ์ ์ฐ๋์? | ๊ณ ์ฑ๋ฅ, ๋์ฉ๋ ๋ค์ด๋ก๋์์ ์ฌ์ฉํฉ๋๋ค (NIO ๊ธฐ๋ฐ) |
flush()๋ ์ ํ์ํ๋์? | ๋ฒํผ์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋คํธ์ํฌ๋ก ๊ฐ์ ์ ์กํฉ๋๋ค |
close() ์ ํ๋ฉด ์ด๋ค ๋ฌธ์ ๊ฐ ์๊ธฐ๋์? | ํ์ผ ํธ๋ค์ด ์ด๋ ค ์์ด GC๊ฐ ์ ๋ฆฌ ๋ชป ํ๊ณ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ์ |
try-with-resources์ ์ฅ์ ์? | close ๋๋ฝ ์์ด ์๋ ๋ฆฌ์์ค ์ ๋ฆฌ โ ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ โ |
โ ๋ง๋ฌด๋ฆฌ ์์ฝํ
ํญ๋ชฉ | ์ค๋ช | ๋ฉ๋ชจ๋ฆฌ ์ํฅ |
---|---|---|
Stream ๋ฐฉ์ | ์ผ๋ฐ ๋ค์ด๋ก๋ ์ฒ๋ฆฌ | buffer ํฌ๊ธฐ๋งํผ๋ง ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ |
ByteBuffer ๋ฐฉ์ | ๊ณ ์ฑ๋ฅ NIO ๊ธฐ๋ฐ | direct memory ํ์ฉ์ผ๋ก GC ๋ถ๋ด โ |
flush() | ๋ฒํผ โ ํด๋ผ์ด์ธํธ ์ ์ก | ์ ์ก ๋๋ฝ ๋ฐฉ์ง |
close() | ์์ ํด์ | ์ ํ๋ฉด ๋์ ๋ฐ์ |
try-with-resources | ์๋ close | ๋ฉ๋ชจ๋ฆฌ ์์ ์ฑ ์ต๊ณ ๐ |