34
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-02-08

はじめに

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

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

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

<!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にします。これで、同じファイルをもう一度読むことができるようになりました。
完成版のコードは以下のとおりです。

<!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で試しています。

34
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?