2024-09-21|閱讀時間 ‧ 約 8 分鐘

【Javascript】檔案資料處理:透過瀏覽器讀取本機檔案進行文字操作

案例情境

工作上固定頻率會收到User提供的設定需求資訊,檔案大多為Excel的格式.xlsx.xls,需要擷取內容的參數資訊,轉換撰寫sql語法寫入資料庫進行操作。

既然格式都是固定的,何不動手寫個小工具,一鍵完成轉換呢?如此一來,不管設定資料的數量多寡都能瞬間完成處理。更重要的是,萬一User臨時變更需求,只要對方重新提供新的設定檔,作業都是瞬間完成的事,而且程式化也能避免人工手動鍵入更新的錯誤,蠻值得花點時間試試。

實作方式

  1. 將Excel另存成utf-8編碼的csv檔案,避免中文顯示亂碼或問號出現。
  2. 用程式讀取檔案,取得內容參數。
  3. 撰寫程式邏輯,整理輸出成想要的格式。


實作考量

雖然本次主要介紹透過瀏覽器進行處理,但在之前已經先用其他語言進行過實作,下面分別探討實作方式的考量:

Python

既然目標是對本機檔案的讀寫操作,首選一定是後端語言出發,其中最簡單的方式非Python莫屬,只不過,如果受限於公司資訊部門防火牆政策,本機可能無法進行下載或安裝。


Java

如果公司本身使用的語言是Java,大多不會有問題,甚至可以打包輸出成可執行的jar檔,提供給同事們使用。但,除非系統開發上需要,我個人並不喜歡用Java的檔案讀寫處理簡單的小程式。FileReader、FileInputStream、BufferedInputStream或是第三方apacheFileUtilsJava 8Files等等,雖然提供多種方式以應對多樣的使用場景,同時也造成選擇困難。


Javascript

使用Node.js來說,呼叫同步的readFileSync使用上跟Python不會差太多,呼叫非同步的readFile則需要注意實作上的差異,等待callback完成才會讀到資料。同樣,Nodejs也可能會因防火牆政策而不能下載或安裝。

前端網頁其實可以進行檔案上傳跟下載,是否也意味著可以上傳後讓網頁取得檔案,進行處理後,再提供下載功能呢?可行的話,寫好的程式也可以分享出去,畢竟公司內電腦總不會限制不給裝瀏覽器吧?


動手試試

基本版型

打開vscode,新建一個html檔案,鍵入!快速建立版型。

body區塊內加入input標籤,並且type="file"


用瀏覽器打開index.html確認結果,點擊選擇檔案會叫出檔案總管,可以選擇要上傳的檔案。

展示

為了方便使用,加入一個點擊按鈕及一個展示區塊,並且給定展示區塊呈現大小。

<style>
#display_area {
width: 800px;
height: 600px;
}
</style>

<body>
<input type="file" id="source">
<hr>
<button id="display_btn">顯示</button><br>
<textarea id="display_area"></textarea>
</body>

程式邏輯

  1. 習慣上我會把script標籤放在head區塊,在document加入事件監聽器,確保DOM載入完成後才觸發執行main
  2. 腳本語言通常不會有主要的程式進入點,因此我還是會加入一個main function
    由於main function只會執行一次,不會進行複用,也可以inline進去上方監聽的程式中,改以匿名函式ES6的箭頭函式的寫法,只是我個人不喜歡很多層的巢狀。
  3. main中,選取顯示的按鈕並加入監聽click事件,事件觸發handleDisplay
  4. 顯示按鈕點擊觸發後,使用瀏覽器的File api讀取上傳檔案,並將檔案內容以文字進行讀取。
  5. 讀取完成拿到檔案內容,將內容更新到顯示區塊中。
<script>
document.addEventListener("DOMContentLoaded", main);

function main() {
const displayBtn = document.querySelector("#display_btn");
displayBtn.addEventListener("click", handleDisplay);
}


function handleDisplay() {
const source = document.querySelector("#source");
const displayArea = document.querySelector("#display_area");
const file = source.files[0];

const fileReader = new FileReader();
fileReader.readAsText(file);
fileReader.onload = (event) => {
const fileContent = event.target.result;
displayArea.innerHTML = fileContent;
}
}
</script>
  1. 最後把結果丟給AI幫忙做點調整跟優化,加入防呆的錯誤處理跟檔案類型限制,完整程式碼如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#display_area {
width: 800px;
height: 600px;
border: 1px solid #ccc;
padding: 10px;
overflow: auto;
white-space: pre-wrap;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", () => {
const displayBtn = document.querySelector("#display_btn");
displayBtn.addEventListener("click", handleDisplay);
});

function handleDisplay() {
const source = document.querySelector("#source");
const displayArea = document.querySelector("#display_area");
const file = source.files[0];

if (!file) {
displayArea.textContent = "No file selected.";
return;
}

if (!file.type.match('text.*')) {
displayArea.textContent = "Invalid file type. Please select a text file.";
return;
}

const fileReader = new FileReader();
fileReader.readAsText(file);

fileReader.onload = (event) => {
const fileContent = event.target.result;
displayArea.textContent = fileContent;
};

fileReader.onerror = () => {
displayArea.textContent = "Error reading file.";
};
}
</script>
</head>
<body>
<input type="file" id="source">
<hr>
<button id="display_btn">顯示</button><br>
<div id="display_area"></div>
</body>
</html>

成果

選擇本機一個spring-boot專案的pom.xml為例,點擊顯示後,內容顯示在下方文字區塊內。



結語

總結一下,上述內容做到的僅有讀取本機上的檔案,將讀到的內容顯示在網頁上,內容即為fileContent

至於資料可以自行使用javascript語法對fileContent做調整,例如處理csv檔案,可透過split處理\r\n拿到每一行,再對,分割取得每一項參數資料值,整理好資料再展示到畫面上。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.