python / nodejs file 다루기
Front-End에서 file 다루기
• input tag
<input id="file-box" type="file" />
const $fileBox = document.querySelector("#file-box");
console.log($fileBox.value) 선택한 file 경로
console.log($fileBox.files) 선택한 file 정보
• multipart/form-data
form 요소에 여러 입력이 있어 content-type이 서로 다를 경우, 이를 서버에서 처리하기 위해 enctype을 multipart/form-data로 정의해줍니다.
<form enctype="mulipart/form-data">
const formData = new Form()
fetch("http://localhost:3000", {
method: "POST",
body: formData
})
// new Form을 넣어서 보내면, 자동으로 mulipart/form-data로 전송됩니다.
• fileReader
file을 비동기로 읽은 web api입니다.
- onload
file이 load되었을때 실행되는 event listener입니다.
- readAsText
file을 text로 읽습니다.
- readAsArrayBuffer
file을 array buffer로 읽습니다.
- readAsDataURL
file을 array buffer로 읽습니다. (base64로 인코딩됩니다.)
- result
file을 읽은 결과를 반환하며, 데이터 형식은 읽기 작업(readAsText, readAsArrayBuffer 등)에 의해 정해집니다.
<input id="file-box" type="file" />
const $fileBox = document.querySelector("#file-box");
<script>
$fileBox.addEventListener("change", (ev) => {
const reader = new FileReader();
reader.onload = (e) => console.log(e.target.result);
reader.readAsText(ev.target.files[0])
})
</script>
• blob
blob은 멀티미디어(이미지/사운드/비디오 등)을 다루기 위한, js 자료형입니다.
const blob = new Blob(array[, option])
🔎 file 또한 특정한 blob의 형태입니다.
- ArrayBuffer
ArrayBuffer는 byte로 이루어진 배열로, binary data를 저장하는 공간입니다. 만일 new ArrayBuffer(32)로 buffer를 만든다면, 32 byte의 저장공간을 만든것과 같습니다. 이 공간은 view interface(Int8Array, Int16Array 등)를 통해 읽고/쓸수 있습니다.
const buffer = new ArrayBuffer(16); //16byte 메모리 공간
const uint8s = new Uint8Array(buffer); // buffer를 unsigned 8bit의 저장소로 읽고/쓸수 있으며, unsigned 8bit이기에 0~255의 수를 8개의 공간에 할당할 수 있습니다.
(int16Array라면, -128 ~ 127 )
python file 다루기
• 파일 열기
- open
file 객체를 반환합니다.
f = open([file 경로], [모드])
🔎 모드는 w(쓰기)/r(읽기)/a(추가)가 있습니다.
• 파일 닫기
open으로 열려있는 file객체를 close로 닫아줍니다.
f.close()
nodejs file 다루기
• 파일 열기
- fs.open
fs.open은 file을 엽니다.
fs.open([file 경로], [w|r|a], (err, fd) => {
...
});
• multer
multer는 multipart/form-data를 다루기 위한 라이브러리입니다.
- 설치
npm install --save multer
- 예시 코드
<!-- client -->
<form action="/profile" method="post" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
// server
const express = require('exress');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express()
app.post('/upload', upload.single('avatar'), (req, res, next) => {
...
//req.body에 담겨져있습니다.
})
- configuration
const upload = multer({
dest: '/dist' // 저장될 directory 이름
limit: { fileSize: 10 * 1024 * 1024 } // file 제한
fileFilter: ... // 어떤 file을 다룰지 정의
preserverPath: ...
})
- disk storage
const upload = multer({
// server disk에 저장하며, destination/filename 정의합니다.
storage: multer.diskStorage({
// disk에 저장되는 directory를 설정합니다.
destination(req, file, cb) {
cb(null, [directory 이름])
}
// disk에 저장되는 file 이름을 설정합니다.
filename: (req, file, cb) => {
cb(null, [file 이름])
}
})
})
- middleware
multer는 middleware로 작동하여, single, array, field, none, any로 form에서 요청온 file들을 처리할 수 있습니다. multer는 이들 요청을 처리한 후 라우터 핸들러에 file 정보를 담아 보냅니다.
(text type은 body에 담는듯?)
- single
단일 field에서 보내진 하나의 file을 처리하고, file 정보를 req.files에 담습니다.
app.post("/upload", upload.single("my-id"), (req, res, next) => {
console.log(req.file);
});
// my-id field를 처리합니다.
- array
단일 field에서 보내진 여러개의 file들을 처리하고, file 정보를 req.files에 담습니다.
app.post("/upload", upload.array("my-id"), (req, res, next) => {
console.log(req.files);
});
// my-id field를 처리합니다.
- field
여러 field에서 보내진 여러개의 file들을 처리하고, file 정보를 req.files에 담습니다.
app.post(
"/upload",
upload.single([{ name: "my-id" }, { name: "your-id" }]),
(req, res, next) => {
console.log(req.files);
}
);
// my-id, your-id field를 처리합니다.
🔎 field 이름은 form에서 정의됩니다.
• socketio
- 데이터 보내기
// client
const handleChangeFileInputREST = async (ev) => {
const file = ev.target.files[0];
const formData = new FormData();
formData.append("image", file);
const res = await fetch("/portfolios/memos", {
method: "POST",
body: formData,
});
console.log(await res.json());
};
// client
const handleChangeFileInput = (ev) => {
setFiles(ev.currentTarget.value);
const reader = new FileReader();
const file = ev.currentTarget.files[0];
console.log(file.type);
console.log(file.name);
console.log(file.size);
reader.readAsArrayBuffer(ev.currentTarget.files[0]);
reader.onload = () => {
console.log(reader.result);
currentSocket.emit("file-upload", {
type: "file-upload",
payload: { binary: reader.result, mime: file.type, name: file.name },
auth: { token },
});
};
};
// server
export async function fileUpload(data) {
try {
const namespace = this.nsp;
const { binary, mime, name } = data.payload;
const filePath = path.join(__dirname, "files");
const lastDotIdx = name.lastIndexOf(".");
const extension = name.substring(lastDotIdx);
fs.openSync(`${filePath}/${name}`, "w");
fs.writeFileSync(`${filePath}/${name}`, binary);
const serviceKey = path.join(__dirname, "..", "config/gcp_bucket_key.json");
const storage = new Storage({ keyFilename: serviceKey });
const bucketname = "vos-bucket";
const res = await storage.bucket(bucketname).upload(`${filePath}/${name}`, {
destination: `memo_files/${name}`,
});
const url = res[0].metadata.mediaLink;
// namespace.in(bookmarkId).emit('file-upload', {
// type: 'file-upload',
// status: 'success',
// message: 'file uploaded',
// payload:"..."
// })
// https://storage.googleapis.com/vos-bucket/memo_files/a
// console.log(res)
} catch (error) {
this.emit("edit-memo", {
type: "edit-memo",
status: "error",
message: error.message,
});
}
}
참고자료
• python 파일 읽기/쓰기
• mime type mdn
• javascript csv - a
• javascript csv - b
• javascript csv - c
• javascript csv - d
• form enctype 종류
• mutipart/form-data
• FileReader API
• FileReader API (readAsTest)
• FileReader API (onload)
• FileReader API (readAsArrayBuffer)
• FileReader API (readAsDataUrl)
• blob mdn
• ArrayBuffer mdn
• ArrayBuffer