파일 시스템 접근
파일 시스템 API를 사용해서 폴더/파일을 읽기/수정할 수 있습니다. 과거에는 파일 조회만 가능했으나 읽기/수정이 가능해지므로써 브라우저 기반 도구에서 작업 후 기기에 데이터를 저장할 수 있게 되었습니다.
브라우저 지원 범위
- 대부분 Chrome / Edge / Opera에서 지원하고, 모바일에서는 미지원한다.
- Browser compatibility
코드 예제
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>File System</title>
</head>
<body>
<div>
<button type="button" data-button-getFile>Get File</button>
<button type="button" data-button-getDir>Get Directory</button>
<p data-message></p>
</div>
<hr />
<div>
<button type="button" data-button-createDir>Create Directory</button>
<p data-message2></p>
</div>
<hr />
<div>
<button type="button" data-button-createFile>Step 1. Create File</button>
<button type="button" data-button-closeFile>Step 2. Close File</button>
<button type="button" data-button-readFile>Step 3. Read File</button>
<p data-message3></p>
<textarea style="display: none; width: 200px; height: 200px"></textarea>
</div>
</body>
</html>
js
const setMessage = (selector, message) => {
document.querySelector(selector).textContent = message;
};
const getFile = async () => {
try {
const [fileHandle] = await window.showOpenFilePicker({
types: [{
description: 'Images',
accept: {
'image/*': ['.png', '.gif', '.jpeg', '.jpg']
}
}, ],
excludeAcceptAllOption: true,
multiple: false
});
setMessage('[data-message]', `fileHandle.kind is ${fileHandle.kind}`)
} catch (error) {
setMessage('[data-message]', `error: ${error}`)
}
}
const getDir = async () => {
try {
const dirHandle = await window.showDirectoryPicker({
mode: 'read',
startIn: 'desktop'
});
setMessage('[data-message]', `dirHandle.kind is ${dirHandle.kind}`)
} catch (error) {
setMessage('[data-message]', `error: ${error}`)
}
}
const createDir = async () => {
try {
const dirHandle = await window.showDirectoryPicker({
mode: 'readwrite',
startIn: 'desktop'
});
const directoryName = `new-${Date.now()}`;
await dirHandle.getDirectoryHandle(directoryName, {
create: true
})
setMessage('[data-message2]', `${directoryName} is created. please check your directory`);
} catch (error) {
setMessage('[data-message2]', `error: ${error}`)
}
}
const state = {
writableStream: null,
text: '',
};
const createFile = async () => {
try {
setMessage('[data-message3]', `creating`);
const fileHandle = await window.showSaveFilePicker();
state.writableStream = await fileHandle.createWritable();
document.querySelector('textarea').style.display = 'block';
document.querySelector('textarea').addEventListener("change", handleChangeText);
setMessage('[data-message3]', `success! 텍스트를 작성해보세요.`);
} catch (error) {
setMessage('[data-message3]', `error: ${error}`)
}
};
const closeFile = async () => {
try {
setMessage('[data-message3]', `saving`);
await state.writableStream.close();
setMessage('[data-message3]', `success! 생성한 파일을 열어보세요.`);
} catch (error) {
setMessage('[data-message3]', `error: ${error}`)
} finally {
state.text = '';
state.writableStream = null;
document.querySelector('textarea').style.display = 'none';
document.querySelector('textarea').removeEventListener("change", handleChangeText);
}
}
const readFile = async () => {
try {
setMessage('[data-message3]', `reading`);
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
const text = await file.text();
const writableStream = await fileHandle.createWritable();
state.text = text;
state.writableStream = writableStream;
document.querySelector('textarea').style.display = 'block';
document.querySelector('textarea').textContent = text;
setMessage('[data-message3]', `success`);
} catch (error) {
setMessage('[data-message3]', `error: ${error}`)
}
};
const handleChangeText = async (event) => {
await state.writableStream.write({
type: "truncate",
size: 0
});
await state.writableStream.write({
type: "write",
position: 0,
data: event.target.value
});
};
const main = () => {
document
.querySelector("[data-button-getFile]")
.addEventListener('click', getFile);
document
.querySelector("[data-button-getDir]")
.addEventListener('click', getDir);
document
.querySelector("[data-button-createDir]")
.addEventListener('click', createDir);
document
.querySelector("[data-button-createFile]")
.addEventListener('click', createFile);
document
.querySelector("[data-button-closeFile]")
.addEventListener('click', closeFile);
document
.querySelector("[data-button-readFile]")
.addEventListener('click', readFile);
};
main();