JavaScriptで同じローカルファイルをもう一度読み込む

# はじめに

JavaScriptでローカルファイルを読み込む場合、同じファイルをもう一度読み込もうとしても、必要なイベントが発火せずファイルを読み込むことができません。これは、その対処方法を検討したメモです。

# ローカルファイルの読み込み

以下のプログラムはローカルのテキストファイルを読み込んで、ブラウザ上に表示するだけのサンプルプログラムです。```clear```ボタンは表示しているテキストを消去します。
この```Choose File```ボタンを押して適当なテキストファイルを読み込むと、画面上にその内容が表示されます。次に```clear```ボタンでテキストを消去し、もう一度```Choose File```を押して先ほどと同じファイルをオープンしても何も表示されません。もちろん、違うファイルを指定すればきちんと表示されます。
これはブラウザが直前に読んだファイル名を覚えており、同じファイルだと```change```イベントを発火しないようにしているためです。

```HTML
<!DOCTYPE html>
<html lang="jp">
<head>
    <title></title>
    <meta charset="UTF-8">
    <script>
    function fileInput(e) {
        for (var i = 0, f; f = e.target.files[i]; i++) {
            if (!f.type.match('text')) continue;

            var reader = new FileReader();

            reader.onload = function(e) {
                var result = document.getElementById('result');
                result.innerText = e.target.result;
            };

            reader.readAsText(f);
        }
    }

    function clearResult() {
        document.getElementById('result').innerText = '';
    }

    window.addEventListener('DOMContentLoaded', function() {
        document.getElementById('fileinput').addEventListener('change', fileInput);
        document.getElementById('clear').addEventListener('click', clearResult);
    });
    </script>
</head>
<body>
    <input type="file" name="fileinput" id="fileinput" value="">
    <input type="button" name="clear" value="clear" id="clear">
    <div id="result"></div>
</body>
</html>
```

# 対処方法

直前に読み込んだファイル名を消すことができれば、もう一度同じファイルを読み込めそうです。ただ、```change```イベントが発火しないので、上記のコードではそもそも```Choose File```のボタンを押されたことも拾うこともできません。
そこで、ボタンが押されたことを検出するために```click```イベントを使います。```click```イベントは```change```イベントより前に起きるので、この中で対処できれば```change```イベントも発火しそうです。調べてみると```this.value```がファイル名を保持しているので、これを```null```にします。これで、同じファイルをもう一度読むことができるようになりました。
完成版のコードは以下のとおりです。

```HTML
<!DOCTYPE html>
<html lang="jp">
<head>
    <title></title>
    <meta charset="UTF-8">
    <script>
    function fileInput(e) {
        for (var i = 0, f; f = e.target.files[i]; i++) {
            if (!f.type.match('text')) continue;

            var reader = new FileReader();

            reader.onload = function(e) {
                var result = document.getElementById('result');
                result.innerText = e.target.result;
            };

            reader.readAsText(f);
        }
    }

    function clearResult() {
        document.getElementById('result').innerText = '';
    }

    // 保持しているファイル名を消す
    function clearFilePath(e) {
        this.value = null;
    }

    window.addEventListener('DOMContentLoaded', function() {
        document.getElementById('fileinput').addEventListener('change', fileInput);
        document.getElementById('fileinput').addEventListener('click', clearFilePath);
        document.getElementById('clear').addEventListener('click', clearResult);
    });
    </script>
</head>
<body>
    <input type="file" name="fileinput" id="fileinput" value="">
    <input type="button" name="clear" value="clear" id="clear">
    <div id="result"></div>
</body>
</html>
```

# 終わりに
分かってしまえば簡単なことでしたが、実際のプログラムで起きたので悩んでしまいました。同じファイルは再読み込みしないという仕様は知りませんでした。
上記のコードはosxのsafariとchromeで試しています。