今回は html で文字列を
ローカルに保存する場合の
ソースを公開してみようと思います。
名前を付けて保存機能があるブラウザでは
名前を付けて保存で保存します。
Chrome や Edge が該当します。
名前を付けて保存機能が無いブラウザでは
直接ダウンロードします。
今回のソースコード
let fileName = document.getElementById('fileNameTextBox').value;
const pattern = /[\\\/:\*\?\"<>\|]/;
if(pattern.test(fileName)){
window.alert('ファイル名に使用できない文字が含まれています。');
}
else {
const save = ""; //この save 変数に保存する文字列を入れて下さい。
if(fileName == ''){
var dt = new Date();
var y = '' + dt.getFullYear();
var m = ('00' + (dt.getMonth()+1)).slice(-2);
var d = ('00' + dt.getDate()).slice(-2);
var hour = ('00' + dt.getHours()).slice(-2);
var minute = ('00' + dt.getMinutes()).slice(-2);
var second = ('00' + dt.getSeconds()).slice(-2);
fileName = "〇〇バックアップ" + (y + m + d + hour + minute + second); //〇〇にはサイト名を入れて下さい。
}
if(typeof window.showSaveFilePicker != 'function'){
const blob = new Blob([save],{type:"text/plain"});
let downloadTag = document.createElement('a');
downloadTag.href = URL.createObjectURL(blob);
downloadTag.download = fileName + ".txt";
downloadTag.click();
window.setTimeout( function() { URL.revokeObjectURL(blob);}, 10000 );
window.alert('バックアップを保存しました。');
} else {
let downloadTag = document.createElement('a');
downloadTag.addEventListener('click', async () => {
const opts = {
suggestedName: fileName,
types: [{
description: 'Text file',
accept: {'text/plain': ['.txt']},
}],
};
try{
const handle = await window.showSaveFilePicker(opts);
const writable = await handle.createWritable();
await writable.write(save);
await writable.close();
window.alert('バックアップを保存しました。');
} catch(e){
}
})
downloadTag.click();
}
}
上記コードでは
ファイル名はファイル名のテキストボックスを
用意するようにしていますが
ファイル名をこちらで指定してしまう事もできます。
セーブデータを圧縮して保存する場合
ブラウザでセーブデータを
圧縮して保存したい事は稀だとは思いますが、
セーブデータを圧縮して保存する場合は
以下のコードにすると良いでしょう。
async function save() {
let fileName = document.getElementById('fileNameTextBox').value;
const pattern = /[\\\/:\*\?\"<>\|]/;
if(pattern.test(fileName)){
window.alert('ファイル名に使用できない文字が含まれています。');
}
else {
let save = 'SaveDataTypeA!ver1.0.0!';
let saveOne = ""; //ここに保存する文字列を入れて下さい。
const readableStream = new Response(saveOne).body.pipeThrough(new CompressionStream('deflate'));
save += await bolbToBase64(await new Response(readableStream).blob());
if(fileName == ''){
var dt = new Date();
var y = '' + dt.getFullYear();
var m = ('00' + (dt.getMonth()+1)).slice(-2);
var d = ('00' + dt.getDate()).slice(-2);
var hour = ('00' + dt.getHours()).slice(-2);
var minute = ('00' + dt.getMinutes()).slice(-2);
var second = ('00' + dt.getSeconds()).slice(-2);
fileName = "〇〇バックアップ" + (y + m + d + hour + minute + second); //〇〇にはサイト名を入れて下さい。
}
if(typeof window.showSaveFilePicker != 'function'){
const blob = new Blob([save],{type:"text/plain"});
let downloadTag = document.createElement('a');
downloadTag.href = URL.createObjectURL(blob);
downloadTag.download = fileName + ".txt";
downloadTag.click();
window.setTimeout( function() { URL.revokeObjectURL(blob);}, 10000 );
window.alert('バックアップを保存しました。');
}
else{
let downloadTag = document.createElement('a');
downloadTag.addEventListener('click', async () => {
const opts = {
suggestedName: fileName,
types: [{
description: 'Text file',
accept: {'text/plain': ['.txt']},
}],
};
try{
const handle = await window.showSaveFilePicker(opts);
const writable = await handle.createWritable();
await writable.write(save);
await writable.close();
window.alert('バックアップを保存しました。');
} catch(e){
}
})
downloadTag.click();
}
}
}
async function bolbToBase64(blob) {
return await new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
resolve(reader.result.replace(/data:.*\/.*;base64,/, ''));
};
});
}
document.getElementById('files').addEventListener('change', function(e) {
var result=e.target.files[0];
var reader=new FileReader();
reader.readAsText(result);
reader.addEventListener('load', function() {
myLoad(reader.result);
});
e.target.value = '';
});
async function myLoad(loadText) {
let index = loadText.indexOf('!');
if(!loadText.startsWith('SaveData')){
window.alert('ファイルの読み込みに失敗しました。');
return;
}
const isTypeA = loadText.startsWith('SaveDataTypeA');
loadText = loadText.substr(index + 1);
index = loadText.indexOf('!');
const versionInfo = loadText.substr(0, index);
loadText = loadText.substr(index + 1);
const oneTimeBlob = await base64ToBlob(loadText);
const readableStream = oneTimeBlob.stream().pipeThrough(new DecompressionStream('deflate'));
loadText = await new Response(readableStream).text();
//ここで loadText をロードしたい変数に代入して下さい。
}
async function base64ToBlob(base64) {
return await fetch('data:application/octet-stream;base64,' + base64).then(res => res.blob());
}
参考サイト:
https://168iroha.net/blog/article/202401031600/
Compression Streams API を使用しています。
API の内部処理が変わってセーブデータが
正常に読み込めなくなった場合に
我々は責任を負わないものとさせて下さい。
何卒よろしくお願い致します。
以上 html で文字列をローカルに
保存するソースを公開しました。
この処理を書く時間を
短縮できたならば幸いです。
皆さんの開発の助けになれますように。
閲覧ありがとうございました。
追記
JavaScript の圧縮関連の
記事を書かれている方から
圧縮の箇所について提案頂きました。
用途ごとの最適な圧縮コードを頂けたため
是非コメント欄もご覧頂けると幸いです。