JavaScriptでテキストファイルを読み込む!FileReader・fetch・配列化・文字化け対策まで完全解説

js-load-textfile javascript
記事内に広告が含まれています。

「ローカルの .txt をブラウザだけで読み込んで中身をサッと確認したい」「サーバーに置いた log.csv を JavaScript で取得してリアルタイム表示したい」――そんなシンプルな要望でも、FileReader・fetch・CORS・文字化けなど壁は意外と多いものです。「とりあえず動くサンプル」はネット上に点在していますが、ローカル・サーバー両方を網羅し、かつエンコーディングや配列化まで“一気通貫”で学べる記事はなかなか見つかりません。そこで本記事では、最小構成のコピペコードから応用テクニック、そしてトラブルシューティングまでをまとめて解説します。これを読めば、テキストファイル読み込みにまつわる迷いが一掃されるはずです。

この記事を読んでわかること

  • FileReader/showOpenFilePicker を使ったローカルファイル読み込みの手順
  • fetch API でサーバー・外部 URL のテキストを取得する方法と CORS 回避策
  • 読み込んだテキストを 1 行ずつ配列化し、変数に保持して再利用するテクニック
  • CSV/TSV/JSON へのパースと HTML への動的表示サンプル
  • 文字化け・BOM・空ファイルなど “よくある問題” の原因と解決策
  1. JavaScriptでテキストファイルを読み込む基本!ブラウザ・サーバーからの読み込みを完全解説
    1. JavaScriptでローカルテキストファイルを読み込む2つの方法【FileReader/showOpenFilePicker】
    2. HTMLとJavaScriptだけで完結!ファイル選択・内容表示の最小構成サンプルコード
    3. サーバー上のテキストファイルをJavaScriptで読み込むには?fetch APIの基本
  2. 読み込んだテキストファイルを思い通りに加工・表示する方法
    1. テキストファイルを1行ずつ読み込み!配列として扱う split('\n') の活用例
    2. 読み込んだテキストデータをJavaScriptの変数に格納して再利用する
    3. CSV/TSV/JSONファイルを読み込んでパース!JavaScriptオブジェクトへの変換術
    4. 読み込んだテキストをHTMLの<textarea>や<div>に表示する具体的な手順
    5. 複数ファイルを同時に読み込む方法とドラッグ&ドロップ実装
  3. JavaScriptテキストファイル読み込みでよくある問題と解決策
    1. 文字化けはこれで解決!Shift-JISやUTF-8のエンコーディング指定と注意点
    2. ファイル読み込み時のエラー処理とセキュリティ対策(CORS/File API制限)
    3. 相対パス・絶対パスでのファイル指定は?開発環境と本番環境での違い
    4. 空ファイルやBOM付きファイルも安心!特殊ケースの読み取り処理
    5. 特定の拡張子(.txt, .csvなど)のみファイル選択を制限する方法
  4. よくある質問(FAQ)
  5. まとめ

JavaScriptでテキストファイルを読み込む基本!ブラウザ・サーバーからの読み込みを完全解説

Webアプリケーション開発において、ユーザーがPC内のファイルをアップロードしたり、サーバー上の設定ファイルを読み込んだりする機能は非常に重要です。本記事では、JavaScriptでテキストファイルを読み込むための基本的な方法から、実践的なテクニック、そしてよくある問題とその解決策まで、Webエンジニアの皆さんが知りたい情報を網羅的に解説します。これを読めば、もうテキストファイルの読み込みで迷うことはありません。

JavaScriptでローカルテキストファイルを読み込む2つの方法【FileReader/showOpenFilePicker】

ユーザーが自分のPCに保存しているテキストファイルをJavaScriptで読み込むには、主にFileReader APIshowOpenFilePicker APIという2つの方法があります。

FileReader APIによる読み込み

FileReader APIは、ユーザーがHTMLの<input type="file">要素を使って選択したファイルの内容を非同期で読み込むためのインターフェースです。対応ブラウザも広く、多くのWebアプリケーションで利用されています。

以下は、FileReader APIを使ってローカルのテキストファイルを読み込み、その内容をコンソールに表示する基本的なコード例です。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FileReader API テキストファイル読み込み</title>
</head>
<body>
    <h1>FileReader APIでテキストファイルを読み込む</h1>
    <input type="file" id="fileInput" accept=".txt">
    <pre id="fileContent"></pre>

    <script>
        document.getElementById('fileInput').addEventListener('change', function(e) {
            const file = e.target.files[0]; // 選択されたファイルを取得

            if (file) {
                const reader = new FileReader(); // FileReaderオブジェクトを作成

                // ファイル読み込みが完了した時のイベントハンドラ
                reader.onload = function(event) {
                    const content = event.target.result; // ファイルの内容を取得
                    document.getElementById('fileContent').textContent = content;
                    console.log('ファイルの内容:', content);
                };

                // ファイル読み込み中にエラーが発生した時のイベントハンドラ
                reader.onerror = function() {
                    console.error('ファイルの読み込み中にエラーが発生しました。');
                };

                // ファイルをテキストとして読み込む
                reader.readAsText(file, 'UTF-8'); // 第二引数で文字コードを指定可能
            } else {
                document.getElementById('fileContent').textContent = 'ファイルが選択されていません。';
            }
        });
    </script>
</body>
</html>

このコードでは、<input type="file" id="fileInput" accept=".txt"> でファイル選択ボタンを作成し、ユーザーがファイルを選択するとchangeイベントが発火します。イベントリスナー内でFileReaderのインスタンスを作成し、readAsText()メソッドでファイルをテキストとして読み込んでいます。読み込みが完了するとonloadイベントが発火し、event.target.resultからファイルの内容を取得できます。

readAsText()の第二引数では、読み込むファイルの**文字コード(エンコーディング)**を指定できます。通常は'UTF-8'を指定しますが、後述する文字化け対策で詳しく解説します。

FileReader - Web API | MDN
FileReader オブジェクトを使用すると、ウェブアプリケーションは、ユーザーのコンピューターに保存されているファイル(または生のデータバッファー)の内容を非同期に読み取ることができます。File または Blob オブジェクトを使用して、読み込むファイルまたはデータを指定します。

showOpenFilePicker APIによる読み込み

showOpenFilePicker APIは、より高度なファイルシステムアクセスを可能にする新しいAPIで、ユーザーがファイルを選択するダイアログを直接開くことができます。FileReaderよりも強力で、ファイルの保存なども可能ですが、まだすべてのブラウザで完全にサポートされているわけではありません(対応状況を確認することが重要です)。

以下は、showOpenFilePicker APIを使った基本的な読み込み例です。

// showOpenFilePicker API を使用したテキストファイル読み込み
async function readFileWithPicker() {
    try {
        // ファイル選択ダイアログを開く
        const [fileHandle] = await window.showOpenFilePicker({
            types: [{
                description: 'Text Files',
                accept: { 'text/plain': ['.txt'] }
            }],
            multiple: false // 複数ファイル選択を許可しない
        });

        // ファイルの内容を取得
        const file = await fileHandle.getFile();
        const content = await file.text(); // ファイルの内容をテキストとして取得

        document.getElementById('fileContent').textContent = content;
        console.log('ファイルの内容:', content);

    } catch (err) {
        console.error('ファイルの選択または読み込みがキャンセル/失敗しました:', err);
        document.getElementById('fileContent').textContent = 'ファイルの読み込みに失敗しました。';
    }
}

// HTMLにボタンを追加してこの関数を呼び出す
// <button onclick="readFileWithPicker()">ファイルを選択(showOpenFilePicker)</button>

showOpenFilePickerは非同期処理であり、async/await構文と組み合わせて使われます。よりモダンで強力なAPIですが、現状では互換性を考慮しFileReaderが広く使われています。

Window.showOpenFilePicker() - Web API | MDN
Window インターフェイスの showOpenFilePicker() メソッドは、ユーザーが単一または複数のファイルを選択できるファイルピッカーを表示し、それらのファイルのハンドルを返します。

次に、HTMLとJavaScriptだけで完結する、より実践的なファイル選択と内容表示のデモを見ていきましょう。

HTMLとJavaScriptだけで完結!ファイル選択・内容表示の最小構成サンプルコード

ここでは、ユーザーがPCからテキストファイルを選択し、その内容をWebページ上の特定の<div>要素に即座に表示する、最もシンプルで実用的な例を紹介します。サーバーサイドの処理は一切不要で、ブラウザだけで完結します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>テキストファイル読み込みデモ</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        #fileInput { margin-bottom: 10px; }
        #outputArea {
            border: 1px solid #ccc;
            padding: 15px;
            min-height: 150px;
            background-color: #f9f9f9;
            white-space: pre-wrap; /* 改行とスペースを保持 */
            word-break: break-all; /* 長い単語でも折り返す */
        }
    </style>
</head>
<body>
    <h1>JavaScriptでテキストファイルを読み込んで表示</h1>

    <p>ローカルPCからテキストファイルを選択してください。</p>
    <input type="file" id="txtFileInput" accept=".txt, .csv, .log">
    <p>ファイル内容:</p>
    <div id="outputArea">
        ここにファイルの内容が表示されます。
    </div>

    <script>
        // HTML要素の取得
        const txtFileInput = document.getElementById('txtFileInput');
        const outputArea = document.getElementById('outputArea');

        // ファイルが選択された時の処理
        txtFileInput.addEventListener('change', (event) => {
            const file = event.target.files[0]; // 選択されたファイルオブジェクトを取得

            // ファイルが選択されなかった場合
            if (!file) {
                outputArea.textContent = 'ファイルが選択されていません。';
                return;
            }

            // FileReaderインスタンスの作成
            const reader = new FileReader();

            // ファイル読み込み完了時のイベントハンドラ
            reader.onload = (e) => {
                const fileContent = e.target.result; // 読み込まれたテキストデータ
                outputArea.textContent = fileContent; // outputAreaに表示
            };

            // ファイル読み込みエラー時のイベントハンドラ
            reader.onerror = (e) => {
                console.error('ファイル読み込みエラー:', e.target.error);
                outputArea.textContent = 'ファイルの読み込み中にエラーが発生しました。';
            };

            // ファイルをテキストとして読み込む
            reader.readAsText(file, 'UTF-8'); // UTF-8エンコーディングで読み込み
        });
    </script>
</body>
</html>

このサンプルコードでは、input type="file"でユーザーがファイルを選択すると、そのchangeイベントを検知してFileReaderが起動します。reader.onload内でファイルの内容を取得し、outputArea (div要素) のtextContentに設定することで、画面に内容が表示されます。非常にシンプルながら、Webアプリケーションにおけるファイル読み込みの基本的な形となります。

サーバー上のテキストファイルをJavaScriptで読み込むには?fetch APIの基本

Webサーバー上にあるテキストファイル(設定ファイル、CSVデータ、JSONデータなど)をJavaScriptで読み込む場合は、主にfetch APIを使用します。fetch APIは、ネットワークリソースを取得するための最新かつ強力なインターフェースであり、Promiseベースで非同期処理をより簡潔に記述できます。

JavaScriptのPromiseをわかりやすく解説!初心者向け入門ガイド
JavaScriptのPromiseを初心者向けにわかりやすく解説!非同期処理の基本概念、then()・catch()の使い方、async/awaitとの違いまで詳しく説明します。コールバック地獄を解消し、スムーズなコードを書けるようになりましょう!
jQueryなしでも大丈夫!Ajax処理を生のjavascriptで行う方法
AjaxとはAsynchronous + JavaScript + XMLの頭文字を使用した非同期処理のことです。jQueryで書くと楽に書くことができます。jQueryでの書き方は以下の記事に書きました。jQueryを使う書き方の記事が多いが実はもうjQueryを使用しなくても簡単にAjax処理が書ける頻繁にAjax...
Ajaxでjsonファイルを読み込んでhtmlを更新する簡単な方法(jQuery使用)
WEBサイトで部分的に更新できるようにしたい場合、そのためにWordPressやMovableTypeなどのCMSを用意するのは少し大がかりすぎるなと思うケースがあります。そんなときにはjsonデータなどの外部ファイルをAjaxで取得して表示させる処理も選択肢に入れれるように流れを覚えておくと良いです。Ajaxとは「A...

fetch APIを使ったテキストファイルの読み込み

fetch APIは、指定したURLからリソースを取得し、そのレスポンスをPromiseとして返します。テキストファイルの場合、レスポンスオブジェクトのtext()メソッドを使うことで、ファイルの内容をテキスト形式で取得できます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>fetch API テキストファイル読み込み</title>
    <style>
        body { font-family: sans-serif; margin: 20px; }
        #serverFileContent {
            border: 1px solid #ccc;
            padding: 15px;
            min-height: 100px;
            background-color: #f0f8ff;
            white-space: pre-wrap;
        }
    </style>
</head>
<body>
    <h1>サーバー上のテキストファイルを読み込む (fetch API)</h1>
    <button id="loadServerFileBtn">サーバーのファイルを読み込む</button>
    <p>サーバーファイル内容:</p>
    <div id="serverFileContent">
        ここにサーバー上のファイルの内容が表示されます。
    </div>

    <script>
        // サーバー上に存在する架空のテキストファイルパス(例: data.txt)
        // 実際には、Webサーバーのルートディレクトリなどに `data.txt` を配置してください
        const SERVER_FILE_URL = 'data.txt'; 
        const loadBtn = document.getElementById('loadServerFileBtn');
        const contentDiv = document.getElementById('serverFileContent');

        loadBtn.addEventListener('click', async () => {
            try {
                // fetch APIを使ってサーバーからテキストファイルを取得
                const response = await fetch(SERVER_FILE_URL);

                // レスポンスが正常かチェック
                if (!response.ok) {
                    throw new Error(`HTTPエラー: ${response.status}`);
                }

                // レスポンスボディをテキストとして取得
                const fileContent = await response.text();

                contentDiv.textContent = fileContent;
                console.log('サーバーファイルの内容:', fileContent);

            } catch (error) {
                console.error('サーバーファイルの読み込みに失敗しました:', error);
                contentDiv.textContent = `エラー: サーバーファイルの読み込みに失敗しました。詳細: ${error.message}`;
            }
        });
    </script>
</body>
</html>

この例では、SERVER_FILE_URLに指定したパス(例えばWebサーバーのルートに置かれたdata.txt)をfetchで取得しています。await response.text()で取得したテキストデータをcontentDivに表示しています。fetchはPromiseを返すため、async/await構文を使うことで、非同期処理を同期処理のように記述でき、可読性が高まります。

XMLHttpRequest (XHR) を使った従来の読み込み方法

fetch APIがモダンな方法ですが、古いブラウザのサポートや、特定の要件からXMLHttpRequest (通称XHR) を使用するケースもまだあります。

// XMLHttpRequest を使用したテキストファイル読み込み(参考)
function loadFileWithXHR(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true); // trueで非同期
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) { // リクエストが完了
            if (xhr.status === 200) { // 正常にレスポンスを受け取った
                callback(null, xhr.responseText);
            } else {
                callback(new Error(`XHRエラー: ${xhr.status}`));
            }
        }
    };
    xhr.onerror = function() {
        callback(new Error('ネットワークエラー'));
    };
    xhr.send();
}

// 使用例:
// loadFileWithXHR('data.txt', (error, content) => {
//     if (error) {
//         console.error(error);
//     } else {
//         document.getElementById('serverFileContent').textContent = content;
//     }
// });

XMLHttpRequestはコールバックベースのAPIであり、Promiseベースのfetchと比較するとコードが複雑になりがちです。特別な理由がない限り、新規開発ではfetch APIを使用することが推奨されます。

読み込んだテキストファイルを思い通りに加工・表示する方法

テキストファイルを読み込むだけでは、多くの場合、目的は達成できません。読み込んだデータを加工したり、特定の形式に変換したり、Webページに整形して表示したりするステップが不可欠です。ここでは、読み込んだテキストデータを最大限に活用するための実践的な方法を解説します。

テキストファイルを1行ずつ読み込み!配列として扱う split('\n') の活用例

読み込んだテキストファイルが複数行にわたるデータ(例:ログファイル、CSVファイルの一部)である場合、各行を個別に処理したいケースが多くあります。JavaScriptでは、split('\n')メソッドを使うことで、テキストを改行コードで分割し、各行を要素とする配列に簡単に変換できます。

// 読み込んだテキストデータの例
const rawText = `Apple
Banana
Orange
Grape
`;

// 1行ずつ配列として分割
let lines = rawText.split('\n');

console.log('元の配列:', lines); // ["Apple", "Banana", "Orange", "Grape", ""]

// 不要な空白行や空要素を削除する場合
lines = lines.map(line => line.trim()).filter(line => line !== '');
console.log('整形後の配列:', lines); // ["Apple", "Banana", "Orange", "Grape"]

// ファイル読み込みと組み合わせる例
// 以下のコードは、前述のFileReaderのonloadイベント内で利用できます。
/*
reader.onload = (e) => {
    const fileContent = e.target.result;
    const lines = fileContent.split('\n').map(line => line.trim()).filter(line => line !== '');
    console.log('読み込んだテキストを1行ずつ配列に:', lines);
    // ここでlines配列を使ってさらに処理を行う
};
*/

split('\n')で分割すると、テキストの最後に改行がある場合、最後の要素が空文字列になることがあります。map(line => line.trim())で各行の前後にある空白(改行コード含む)を削除し、filter(line => line !== '')で空の要素を除外することで、よりクリーンな配列が得られます。

読み込んだテキストデータをJavaScriptの変数に格納して再利用する

読み込んだテキストファイルの内容は、一時的に表示するだけでなく、JavaScriptの内部で変数として保持し、様々な処理に再利用することが一般的です。

let loadedData = ''; // ファイル内容を格納する変数

// FileReaderの場合
document.getElementById('fileInput').addEventListener('change', function(e) {
    const file = e.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function(event) {
            loadedData = event.target.result; // ファイル内容を変数に格納
            console.log('変数に格納されたデータ:', loadedData);
            // ここで loadedData を使って他の処理を呼び出す
            processLoadedData(loadedData);
        };
        reader.readAsText(file);
    }
});

// fetch APIの場合
async function fetchAndStoreData(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) throw new Error('Network response was not ok.');
        loadedData = await response.text(); // ファイル内容を変数に格納
        console.log('変数に格納されたデータ:', loadedData);
        // ここで loadedData を使って他の処理を呼び出す
        processLoadedData(loadedData);
    } catch (error) {
        console.error('データ取得エラー:', error);
    }
}

function processLoadedData(data) {
    // 例: 読み込んだデータを全て大文字にする
    const upperCaseData = data.toUpperCase();
    console.log('処理されたデータ:', upperCaseData);
    // さらにHTML要素に表示するなど
    document.getElementById('processedOutput').textContent = upperCaseData;
}

// <div id="processedOutput"></div>
// <button onclick="fetchAndStoreData('data.txt')">サーバーから読み込む</button>

このように、グローバル変数や、特定のスコープ内の変数に読み込んだデータを格納することで、その後の関数やイベントでデータを自由に加工・利用できるようになります。

CSV/TSV/JSONファイルを読み込んでパース!JavaScriptオブジェクトへの変換術

テキストファイルには、CSV (Comma Separated Values) や TSV (Tab Separated Values) のように構造化されたデータ、あるいはJSON (JavaScript Object Notation) のように直接JavaScriptオブジェクトに変換できる形式もあります。これらのファイルを読み込んで、JavaScriptで扱いやすいデータ構造に変換する方法を見ていきましょう。

HTMLでCSVファイルを読み込む方法まとめ|初心者でも簡単にテーブル表示&文字化け対策まで
CSVファイルをHTMLに読み込んで表示したい!ローカルPCやサーバー上のCSVをJavaScript(FileReader API・fetch API)で簡単にHTMLテーブル化する方法を解説。文字化けやエンコーディング(UTF-8/Shift-JIS)対策、大量データ高速処理、グラフ化やセキュリティ対策まで紹介

CSV/TSVファイルのパース

CSVやTSVは、スプレッドシートのデータをテキスト形式で保存したものです。JavaScriptの文字列操作メソッドを使って、シンプルなCSV/TSVなら簡単にパースできます。

// CSVデータ例
const csvData = `Name,Age,City
Alice,30,New York
Bob,24,London
Charlie,35,Paris
`;

function parseCSV(csvText) {
    const lines = csvText.trim().split('\\n'); // 空白行を削除
    const headers = lines[0].split(','); // ヘッダー行をカンマで分割
    const data = [];

    for (let i = 1; i < lines.length; i++) {
        const values = lines[i].split(','); // 各行をカンマで分割
        const row = {};
        headers.forEach((header, index) => {
            row[header.trim()] = values[index].trim(); // ヘッダーをキーにしてオブジェクトに格納
        });
        data.push(row);
    }
    return data;
}

const parsedCsv = parseCSV(csvData);
console.log('パースされたCSVデータ:', parsedCsv);
/*
[
  { Name: "Alice", Age: "30", City: "New York" },
  { Name: "Bob", Age: "24", City: "London" },
  { Name: "Charlie", Age: "35", City: "Paris" }
]
*/

// TSVも同様に、split('\\t') を使えばパースできます。

このparseCSV関数は、最初の行をヘッダーとして扱い、それ以降の行をデータとしてオブジェクトの配列に変換します。より複雑なCSV(引用符や改行を含む場合)には専用のライブラリ(Papa Parseなど)の利用を検討してください。

JSONファイルのパース

JSONはJavaScriptと非常に親和性が高く、JSON.parse()メソッドを使うだけで簡単にJavaScriptオブジェクトに変換できます。

// JSONデータ例 (文字列として読み込まれた場合)
const jsonString = `[
    { "id": 1, "product": "Laptop", "price": 1200 },
    { "id": 2, "product": "Mouse", "price": 25 },
    { "id": 3, "product": "Keyboard", "price": 75 }
]`;

try {
    const jsonObject = JSON.parse(jsonString);
    console.log('パースされたJSONデータ:', jsonObject);
    /*
    [
      { id: 1, product: "Laptop", price: 1200 },
      { id: 2, product: "Mouse", price: 25 },
      { id: 3, product: "Keyboard", price: 75 }
    ]
    */
} catch (error) {
    console.error('JSONパースエラー:', error);
}

// fetch APIでJSONファイルを読み込む場合
async function fetchAndParseJson(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) throw new Error('Network response was not ok.');
        const jsonContent = await response.json(); // .json()メソッドで直接JSONオブジェクトに変換
        console.log('fetchで取得したJSONデータ:', jsonContent);
        return jsonContent;
    } catch (error) {
        console.error('JSONファイルの取得・パースエラー:', error);
    }
}

// 例: fetchAndParseJson('products.json'); // サーバー上のproducts.jsonを読み込む

fetch APIでJSONを読み込む場合、レスポンスオブジェクトのjson()メソッドを使うと、テキストとして取得してからJSON.parse()する必要がなく、より簡潔に処理できます。

読み込んだテキストをHTMLの<textarea>や<div>に表示する具体的な手順

読み込んだテキストデータをWebページ上に表示する方法は多岐にわたりますが、最も一般的なのは<textarea><div>要素を利用することです。

  • <textarea>: ユーザーが編集可能なテキストエリアに表示する場合に最適です。ファイルの内容をそのまま入力フィールドにしたい場合に便利です。
  • <div>または<pre>: 単に内容を表示するだけで、編集させたくない場合に適しています。特に<pre>要素は、テキストの改行やスペースをそのまま保持して表示するため、コードやログの表示に役立ちます。
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>テキスト表示例</title>
</head>
<body>
    <h1>読み込んだテキストの表示例</h1>

    <input type="file" id="fileToDisplay" accept=".txt">

    <h2>textareaに表示</h2>
    <textarea id="outputTextArea" rows="10" cols="50"></textarea>

    <h2>div (pre) に表示</h2>
    <pre id="outputPre"></pre>

    <script>
        const fileToDisplay = document.getElementById('fileToDisplay');
        const outputTextArea = document.getElementById('outputTextArea');
        const outputPre = document.getElementById('outputPre');

        fileToDisplay.addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = (e) => {
                const content = e.target.result;

                // textareaに表示
                outputTextArea.value = content; // <textarea>には.valueを使う

                // pre要素に表示
                outputPre.textContent = content; // <pre>や<div>には.textContentを使う
            };
            reader.readAsText(file, 'UTF-8');
        });
    </script>
</body>
</html>

textarea要素に表示する場合はvalueプロパティを、divpre要素に表示する場合はtextContentプロパティを使用します。innerHTMLも使えますが、セキュリティ上のリスク(XSS攻撃など)を避けるため、純粋なテキストを表示するだけであればtextContentの使用が推奨されます。

整形されたデータ(例:CSVから変換した表)をHTMLにレンダリングする

CSVやJSONからパースしたデータをHTMLの表 (<table>) やリスト (<ul>) として表示することで、ユーザーにとってより分かりやすい形で情報を提供できます。

<input type="file" id="csvFileInput" accept=".csv">
<div id="tableOutput"></div>

<script>
document.getElementById('csvFileInput').addEventListener('change', async (event) => {
    const file = event.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (e) => {
        const csvText = e.target.result;
        const data = parseCSV(csvText); // 前述のparseCSV関数を使用

        // テーブルを生成して表示
        let tableHtml = '<table><thead><tr>';
        // ヘッダーを生成
        Object.keys(data[0]).forEach(header => {
            tableHtml += `<th>${header}</th>`;
        });
        tableHtml += '</tr></thead><tbody>';

        // データ行を生成
        data.forEach(row => {
            tableHtml += '<tr>';
            Object.values(row).forEach(value => {
                tableHtml += `<td>${value}</td>`;
            });
            tableHtml += '</tr>';
        });
        tableHtml += '</tbody></table>';

        document.getElementById('tableOutput').innerHTML = tableHtml; // innerHTMLでHTML文字列を挿入
    };
    reader.readAsText(file, 'UTF-8');
});
</script>

このように、JavaScriptでHTML要素を動的に生成し、innerHTMLプロパティを使ってDOMに挿入することで、パースしたデータをリッチな形式で表示できます。

複数ファイルを同時に読み込む方法とドラッグ&ドロップ実装

ユーザーが複数のファイルを一度に選択したり、ファイルをWebページにドラッグ&ドロップしたりして読み込めるようにすると、アプリケーションのユーザビリティが向上します。

input type="file"での複数ファイル選択

<input type="file">要素にmultiple属性を追加するだけで、ユーザーはファイル選択ダイアログで複数のファイルを選択できるようになります。JavaScript側では、event.target.filesがファイルオブジェクトのFileList(配列のようなオブジェクト)として取得できます。

<input type="file" id="multipleFileInput" multiple accept=".txt">
<div id="multipleFilesOutput"></div>

<script>
document.getElementById('multipleFileInput').addEventListener('change', async (event) => {
    const files = event.target.files; // 選択された全ファイル

    if (files.length === 0) {
        document.getElementById('multipleFilesOutput').textContent = 'ファイルが選択されていません。';
        return;
    }

    let allContents = '';
    for (const file of files) {
        // 各ファイルをFileReaderで読み込む
        const reader = new FileReader();
        await new Promise((resolve, reject) => {
            reader.onload = (e) => {
                allContents += `--- ${file.name} ---\\n${e.target.result}\\n\\n`;
                resolve();
            };
            reader.onerror = reject;
            reader.readAsText(file, 'UTF-8');
        });
    }
    document.getElementById('multipleFilesOutput').textContent = allContents;
});
</script>

複数のファイルを非同期で読み込むため、Promiseasync/awaitを組み合わせて、各ファイルの読み込みが完了するのを待ってから次の処理に進むようにしています。

ドラッグ&ドロップによるファイル読み込み

ドラッグ&ドロップによるファイル読み込みは、ユーザーにとって直感的な操作性を提供します。これは、dragoverdragleavedropなどのイベントを利用して実現します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ドラッグ&ドロップファイル読み込み</title>
    <style>
        #dropArea {
            width: 300px;
            height: 150px;
            border: 2px dashed #ccc;
            text-align: center;
            line-height: 150px;
            font-size: 1.2em;
            color: #666;
        }
        #dropArea.highlight {
            border-color: #007bff;
            background-color: #e0f2f7;
        }
    </style>
</head>
<body>
    <h1>ファイルをドラッグ&ドロップで読み込む</h1>
    <div id="dropArea">
        ファイルをここにドラッグ&ドロップしてください
    </div>
    <pre id="dndOutput"></pre>

    <script>
        const dropArea = document.getElementById('dropArea');
        const dndOutput = document.getElementById('dndOutput');

        // デフォルトのブラウザの挙動をキャンセル(ファイルが開かれるのを防ぐ)
        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, preventDefaults, false);
        });

        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }

        // ドラッグ中のスタイル変更
        ['dragenter', 'dragover'].forEach(eventName => {
            dropArea.addEventListener(eventName, () => dropArea.classList.add('highlight'), false);
        });

        ['dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, () => dropArea.classList.remove('highlight'), false);
        });

        // ドロップ時の処理
        dropArea.addEventListener('drop', async (e) => {
            const dt = e.dataTransfer;
            const files = dt.files; // ドロップされたファイルリスト

            if (files.length === 0) {
                dndOutput.textContent = 'ファイルがドロップされませんでした。';
                return;
            }

            let allContents = '';
            for (const file of files) {
                // ファイルタイプを確認(例: テキストファイルのみ許可)
                if (file.type && !file.type.startsWith('text/')) {
                    allContents += `--- ${file.name} --- (テキストファイルではありません)\\n\\n`;
                    continue;
                }

                const reader = new FileReader();
                await new Promise((resolve, reject) => {
                    reader.onload = (event) => {
                        allContents += `--- ${file.name} ---\\n${event.target.result}\\n\\n`;
                        resolve();
                    };
                    reader.onerror = reject;
                    reader.readAsText(file, 'UTF-8');
                });
            }
            dndOutput.textContent = allContents;
        }, false);
    </script>
</body>
</html>

ドラッグ&ドロップの実装では、ブラウザのデフォルト挙動をpreventDefault()で停止し、dropイベントでe.dataTransfer.filesからドロップされたファイルを取得します。デザイン面では、ドラッグ中のハイライト表示なども加えることで、ユーザーに分かりやすいUIを提供できます。

JavaScriptテキストファイル読み込みでよくある問題と解決策

JavaScriptでテキストファイルを読み込む際には、文字化けやセキュリティ制約、パスの指定方法など、いくつかの一般的な問題に直面することがあります。ここでは、それらの問題への対処法と、より堅牢な実装のためのヒントを提供します。

文字化けはこれで解決!Shift-JISやUTF-8のエンコーディング指定と注意点

テキストファイルを読み込んだ際に、日本語などが正しく表示されずに「文字化け」する問題はよく発生します。これは、ファイルの文字コード(エンコーディング)と、JavaScriptが読み込む際に指定するエンコーディングが一致しない場合に起こります。

FileReader.readAsText() のエンコーディング指定

FileReader.readAsText()メソッドは、第二引数にエンコーディングを指定できます。これを正しく設定することが文字化け対策の基本です。

// 例: Shift-JISのファイルを読み込む場合
reader.readAsText(file, 'Shift_JIS');

// 例: EUC-JPのファイルを読み込む場合
reader.readAsText(file, 'EUC-JP');

// 例: UTF-8(BOMなし)のファイルを読み込む場合
reader.readAsText(file, 'UTF-8');

ファイルがどの文字コードで保存されているか分からない場合は、いくつかのエンコーディングを試してみるか、ユーザーにエンコーディングを選択させるUIを提供することも検討できます。

BOM (Byte Order Mark) が原因の文字化けと対処法

UTF-8には、ファイルの先頭にBOM(バイトオーダーマーク)が付与されている場合があります。このBOMが原因で、テキストの先頭に不要な文字が表示されたり、JSONのパースに失敗したりすることがあります。

BOM付きUTF-8ファイルを読み込んだ場合、trim()や特定の文字を削除する処理で対応できます。

reader.onload = (e) => {
    let content = e.target.result;
    // BOM(UTF-8の場合)を削除する正規表現
    if (content.charCodeAt(0) === 0xFEFF) {
        content = content.substring(1);
    }
    // または、より汎用的なtrim()を使う
    // content = content.trim();

    console.log('BOM削除後の内容:', content);
    document.getElementById('fileContent').textContent = content;
};

理想的には、ファイル保存時にBOMを付与しない設定で保存することが推奨されます。

ファイル読み込み時のエラー処理とセキュリティ対策(CORS/File API制限)

安全で安定したアプリケーションを開発するためには、ファイル読み込み時のエラー処理と、ブラウザのセキュリティ制約への理解が不可欠です。

エラー処理の基本

FileReaderfetch APIは非同期処理であるため、エラーが発生する可能性があります。try...catchブロックやPromiseの.catch()メソッドを使って、適切にエラーを捕捉し、ユーザーに分かりやすいメッセージを表示することが重要です。

// FileReaderのエラー処理
reader.onerror = function(event) {
    console.error('FileReaderエラー:', event.target.error.name);
    alert('ファイルの読み込み中にエラーが発生しました。ファイルが破損しているか、アクセス権限がありません。');
};

// fetch APIのエラー処理
try {
    const response = await fetch(url);
    if (!response.ok) { // HTTPステータスが200番台以外の場合
        throw new Error(`HTTPエラー: ${response.status} ${response.statusText}`);
    }
    const data = await response.text();
    // 処理
} catch (error) {
    console.error('fetchエラー:', error);
    alert('サーバーからのファイル取得に失敗しました。URLを確認してください。');
}

CORS (Cross-Origin Resource Sharing) の制約

fetch APIXMLHttpRequestを使って、異なるオリジン(ドメイン、プロトコル、ポートのいずれかが異なる)のサーバーからファイルを読み込もうとすると、CORS(Cross-Origin Resource Sharing)のセキュリティ制約によりブロックされることがあります。

この問題は、ファイルを提供するサーバー側で適切なCORSヘッダー(例: Access-Control-Allow-Origin: * または特定のオリジン)を設定することで解決できます。クライアントサイド(JavaScript)からCORSを回避する方法はありません。サーバー側の協力が必要です。

fetchでCORSエラーが出た時の対処法|no-corsやAccess-Control-Allow-Originを解説
fetchで困るCORSエラーを解説!「なぜ?」の仕組み、ブラウザ開発者ツールでのデバッグ、サーバー/クライアントでの具体的解決策(Access-Control-Allow-Origin設定など)、よくある失敗例、ローカル環境対策まで網羅。この記事でCORSエラーを理解し、自信を持って対処できるようになりましょう。

File APIのセキュリティ上の制限

FileReaderを含むFile APIは、ユーザーのローカルファイルシステムへの無制限なアクセスを防ぐため、セキュリティ上の制限があります。

  • ユーザー操作が必須: 通常、input type="file"によるファイル選択や、ドラッグ&ドロップといったユーザーの明示的な操作がなければ、JavaScriptからローカルファイルにアクセスすることはできません。
  • 読み込み専用: JavaScriptからローカルファイルを直接作成したり、既存のファイルを上書きしたりすることはできません(showSaveFilePickerなどの一部APIを除く)。

これらの制限は、ユーザーのプライバシーとセキュリティを守るために設けられています。

相対パス・絶対パスでのファイル指定は?開発環境と本番環境での違い

Webサーバー上のテキストファイルをfetch APIなどで読み込む際、そのファイルのパスをどのように指定するかは重要です。

  • 絶対パス: Webサイトのルートからの完全なパス。例: /data/config.json (ドメインは含まない)。
  • 相対パス: 現在のHTMLファイルからの相対的な位置。例: ./data/config.json (現在のディレクトリ内のdataフォルダ)。

開発環境 vs. 本番環境:

  • 開発環境: ローカルのファイルシステムで直接HTMLファイルを開いている場合、fetchfile://プロトコルで動作しようとするため、多くの場合CORSエラーやセキュリティエラーが発生します。このため、開発時には簡易的なローカルサーバー(例: npm install -g http-server)を立てて作業することが推奨されます。
  • 本番環境: 常にWebサーバー上で動作するため、上記のように絶対パスや相対パスでファイルを指定し、fetchで読み込むことができます。
// 現在のHTMLからの相対パスで指定
const RELATIVE_PATH_URL = './assets/settings.txt';

// ドメインルートからの絶対パスで指定
// 例: <https://example.com/api/data.json>
const ABSOLUTE_PATH_URL = '/api/data.json';

async function loadTextFile(path) {
    try {
        const response = await fetch(path);
        if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
        const content = await response.text();
        console.log(`ファイル (${path}) の内容:`, content);
    } catch (error) {
        console.error(`ファイル (${path}) の読み込みに失敗しました:`, error);
    }
}

// loadTextFile(RELATIVE_PATH_URL);
// loadTextFile(ABSOLUTE_PATH_URL);

ファイルパスの指定は、サーバー側のファイル配置と密接に関連しているため、開発環境と本番環境での挙動の違いを理解しておくことが重要です。

空ファイルやBOM付きファイルも安心!特殊ケースの読み取り処理

通常のテキストファイルだけでなく、特殊な形式のファイル(空ファイル、改行のみのファイル、BOM付きファイルなど)も適切に処理できるように準備しておくことが、堅牢なアプリケーションには不可欠です。

空ファイルの処理

ファイルが空の場合、reader.resultは空文字列になります。この場合、特にエラーとせず、空のデータとして扱えば問題ありません。

reader.onload = (e) => {
    const content = e.target.result;
    if (content.length === 0) {
        console.log('空のファイルが読み込まれました。');
        // 必要に応じてユーザーに通知
        document.getElementById('outputArea').textContent = 'ファイルは空です。';
    } else {
        // 通常の処理
        document.getElementById('outputArea').textContent = content;
    }
};

改行のみのファイルの処理

改行のみのファイルの場合、split('\n')で分割すると空文字列の配列が生成されます。前述のfilter(line => line !== '')を使うことで、不要な空行を除外できます。

BOM(Byte Order Mark)の削除

BOM付きUTF-8ファイルの処理は「文字化けはこれで解決!」のセクションで解説した通り、content.charCodeAt(0) === 0xFEFFでチェックし、substring(1)で削除することで対応できます。

これらの特殊ケースを考慮することで、より安定したファイル読み込み機能を提供できます。

特定の拡張子(.txt, .csvなど)のみファイル選択を制限する方法

ユーザーが誤って画像ファイルなどをテキストファイル読み込み機能にアップロードしてしまうのを防ぐため、ファイル選択ダイアログで許可するファイルの種類を制限できます。これは、<input type="file">要素のaccept属性を使用します。

<input type="file" id="specificFileInput" accept=".txt, .csv">

<input type="file" id="txtOnlyInput" accept="text/plain">

<input type="file" id="imageInput" accept="image/jpeg, image/png">

accept属性には、以下のいずれかを指定します。

  • ファイル拡張子: .txt, .csv, .json など、カンマ区切りで指定します。
  • MIMEタイプ: text/plain, text/csv, application/json, image/jpeg など、MIMEタイプを指定します。

accept属性はあくまでヒントであり、ユーザーがファイルダイアログで「すべてのファイル」を選択すれば、指定外のファイルも選択できてしまいます。そのため、JavaScript側でもファイルの拡張子やMIMEタイプを検証することが推奨されます。

document.getElementById('specificFileInput').addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (file) {
        // ファイル名から拡張子を取得
        const fileName = file.name;
        const fileExtension = fileName.split('.').pop().toLowerCase();

        // MIMEタイプも確認
        const fileMimeType = file.type;

        // 許可する拡張子リスト
        const allowedExtensions = ['txt', 'csv', 'json'];
        // 許可するMIMEタイプリスト
        const allowedMimeTypes = ['text/plain', 'text/csv', 'application/json'];

        if (!allowedExtensions.includes(fileExtension) && !allowedMimeTypes.includes(fileMimeType)) {
            alert('このファイルタイプは許可されていません。txt, csv, jsonファイルを選択してください。');
            e.target.value = ''; // ファイル選択をクリア
            return;
        }

        // ここからファイルの読み込み処理
        // ...
    }
});

accept属性とJavaScriptによる二重チェックを行うことで、より堅牢なファイルタイプ検証を実現できます。

よくある質問(FAQ)

JavaScriptでサーバーのファイルを直接書き換えることはできますか?

いいえ、ブラウザのJavaScript(クライアントサイドJavaScript)から直接サーバー上のファイルを書き換えたり、削除したりすることはできません。これはセキュリティ上の理由で制限されています。サーバー上のファイルを操作するには、Node.jsなどのサーバーサイドJavaScriptやPHP、Pythonなどのサーバーサイド言語を使って、サーバー側のAPIを介して処理を行う必要があります。

ローカルのテキストファイルをJavaScriptで読み込む際、常にユーザーの操作が必要ですか?

基本的に、はい。ブラウザのセキュリティモデルにより、JavaScriptがユーザーの許可なくローカルファイルシステムにアクセスすることは禁じられています。そのため、input type=”file”要素によるファイル選択やドラッグ&ドロップなど、ユーザーの明示的な操作が必須となります。自動的に任意のローカルファイルを読み込むことはできません。

読み込み可能なテキストファイルのサイズに制限はありますか?

明確なサイズ制限はブラウザによって異なりますが、非常に大きなファイル(数十MB〜数GB)を読み込む場合、ブラウザのメモリを大量に消費し、動作が遅くなったり、フリーズしたりする可能性があります。大量のデータを扱う場合は、ファイルを分割して読み込むストリーム処理や、サーバーサイドでの処理を検討する必要があります。FileReaderはファイルをメモリにすべて読み込むため、特に注意が必要です。

モバイルデバイス(スマホやタブレット)でも、JavaScriptのファイル読み込み機能は動作しますか?

はい、現代のモバイルブラウザのほとんどはFileReader APIやfetch APIをサポートしており、PCと同様にJavaScriptでテキストファイルを読み込むことができます。input type=”file”もモバイルデバイスに対応しており、写真ライブラリからの選択や、ファイルアプリからの選択などが可能です。

まとめ

本記事では、JavaScriptでテキストファイルを読み込むための様々な方法を、具体的なコード例を交えて詳しく解説しました。

重要ポイント

  • ローカルファイルの読み込み: FileReader APIshowOpenFilePicker APIを使い、ユーザーがPCから選択したファイルをブラウザ内で処理する方法を学びました。
  • サーバーファイルの読み込み: fetch APIを主軸に、Webサーバー上にあるテキストファイルを非同期で取得する方法を理解しました。
  • データの加工と表示: 読み込んだテキストデータを1行ずつ処理したり、CSV/JSON形式をパースしてJavaScriptオブジェクトに変換したり、HTML要素に整形して表示するテクニックを習得しました。
  • 問題解決: 文字化け、エラー処理、CORS、パス指定、特殊なファイル形式への対応、ファイルタイプ制限など、よくある問題とその解決策についても網羅的にカバーしました。

これであなたは、JavaScriptでテキストファイルを自在に操り、より高度でユーザーフレンドリーなWebアプリケーションを構築するための知識とスキルを手に入れました。ぜひ本記事のコード例を参考に、あなたのプロジェクトに役立ててください。

JavaScript fetchが動かない?POST/GETリクエスト・CORS・戻り値エラーの原因と対処法を完全ガイド
JavaScriptのfetchが使えない原因を徹底解説!GET/POSTの書き方から「Failed to fetch」やCORSエラーの対処法、非同期処理との連携、パースミスの回避まで、fetchが正常に動作しない時にチェックすべきポイントを紹介します。実践向けコード付きで、よくあるミスや疑問もまるごと解決!
ゼロから分かる!JavaScriptドラッグアンドドロップ並び替え実装術|コード例・ライブラリ比較・高機能UIの作り方
JavaScriptでドラッグ&ドロップによる並び替え機能を実装したい方へ。ネイティブJSやHTML5 APIの基本から、スマホ対応、アニメーションの付け方、Sortable.jsなどのライブラリ活用法まで解説します。並び替えた順序の取得・保存方法や、React/Vue対応、パフォーマンス最適化のコツも網羅!
タイトルとURLをコピーしました