从文本文件中读取而不使用javascript中的事件

时间:2014-09-06 10:27:40

标签: javascript html

以下在触发和选择文件时有效,但我甚至不想在这种情况下使用该事件,我希望文件从路径自动加载并逐行读取。

<input type="file" id="fileinput" />
<script>
function readSingleFile(evt){

    //Retrieve the first (and only!) File from the FileList object
    var f = evt.target.files[0]; 

    if(f){
        var r = new FileReader();
        r.onload = function(e) { 
            var contents = e.target.result;
            // Some code
        }
        r.readAsText(f);
    }else{ 
        alert("Failed to load file");
    }
}
document.getElementById('fileinput').addEventListener('change', readSingleFile, false);
<script>

2 个答案:

答案 0 :(得分:1)

来自用户操作系统的文件加载必须由某种形式的用户事件触发,除了从canvas元素获取文件对象(这可以直接生成)。

正如excerpt from MDN所述:

  

可以从用户使用元素,拖放操作的DataTransfer对象或HTMLCanvasElement上的mozGetAsFile()API选择文件返回的FileList对象中获取文件对象。

允许网页在没有用户干预或明确许可的情况下从用户的计算机加载任何文件的能力确实是危险的。但是,根据您对文件(或主机环境)的处理方式,您可以选择一些选项。


通过AJAX / XHTTP加载文件

我包含了我通过file://协议使用的源代码,因此在本地下载jQuery的原因,而不是使用任何热链接等效。为了测试这个,您只需要下载jQuery并将其保存在与此HTML文件相同的目录中,显然要么创建textfile.txt,要么将代码更改为指向另一个文件。

  

注意:文件路径应保留在您的Web根目录中,并且可以从同一主机下的Web服务器访问,除非您在本地运行file://协议中的代码。如果您正在使用file://协议,只要您的浏览器具有访问所述文件的权限,您就可以从计算机上的任何位置加载文件,并且仍然可以通过file://进行访问。

以这种方式加载文件(或我在页面上提到的任何其他方法)与您在问题中加载文件的方式有一个很大的区别。通过文件选择器对话框加载文件是从用户自己的计算机获取文件;而通过AJAX(或通过脚本/ iframe标签)加载文件是从服务器获取文件。这是否会破坏你的目标将取决于你究竟用它做什么。永远不会加载文本文件最好通过这种方法完成,下面你会发现一些其他的二级方法确实有它们的好处,但也有一些缺点。

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Load a text file</title>
<script src="jquery.js"></script>
<script>
  jQuery 
    .ajax({
      url: 'textfile.txt',
      dataType: 'text'
    })
    .error(function(){
      console.warn('An error occurred whilst loading the file', arguments);
    })
    .done(function(res){
      jQuery.each(res.split(/\r?\n/g), function(i, v){
        jQuery('#output').append('<p>' + v + '</p>');
      });
    })
  ;
</script>
</head>
<body>
  <h1>Fileload</h1>
  <div id="output"></div>
</body>
</html>


通过脚本标记

加载文件

此选项要求您修改文本文件以包含少量JavaScript,然后允许您使用普通脚本标记导入其内容。与AJAX不同,这不受跨源阻止,即 stackoverflow.com 可以从 gamedev.stackexchange.com 请求文件。这种方法还具有占用空间小的优点。

  

注意:现在,AJAX请求可以在实施CORS时可靠地解决跨源问题。但是,这通常涉及对服务器端进行一些控制。

此方法的缺点是您必须修改文本文件,将文本文件解析为JavaScript(意味着某些高阶字符可能会破坏较旧的解析器),并且您正在滥用Function.toString()。如果您对使用多行黑客评论感到不满意,可以轻松地将文本文件修改为implement multiline strings the proper way using string concatenation instead。但是一旦你这样做,你就会远离加载像纯文本文件这样的东西。

您的文字内容

(typeof loadfile != 'undefined') && loadfile(function(){/*
Place your text file contents here.
We are abusing the JavaScript comment facility
to achieve multiline strings without too much
modification to your original text file.
*/});
主页中的

脚本

<script>
/**
 * This function is responsible for receiving the function
 * sent by your text file
 */
function loadfile(content){
  var text = String(content && content.toString()),
      p1 = text.indexOf('/*')+2,
      p2 = text.lastIndexOf('*/')
  ;
  console.log(text.substring(p1, p2));
};
</script>
<script src="your-text-file.txt.js"></script>


通过iframe加载文件

这个选项几乎就是以前使用的 - 如果没有服务器端可用 - 在AJAX流行之前。除了使用轮询来关注iframe何时准备好时,管理iframe的代码更小,跨浏览器更可靠,因此它与AJAX没有任何好处。使用AJAX,通常最好依靠库(如jQuery)来处理不同环境之间的差异。

然而,这就是说AJAX为你提供了更多的能力,以及更多的互动反馈,以及(在更好地支持事件的情况下)发生的事情。依赖轮询可能更慢/不可靠,但它是iframe的唯一选择,因为并非所有浏览器都支持触发正确的事件,尤其是在处理意外数据类型时。

这是我曾经使用的一个脚本,我已经整理和更新,只是为了说明这一点。如果你想在旧浏览器中使用它,那么此版本依赖于Object.create so you will need a polyfill;但正如我已多次陈述的......如果可以,请使用AJAX,如果你不能,那么你的方法可能需要重新思考。

/**
 * Textfile
 *
 * Allows the loading of a textfile via an iframe or script tag.
 *
 * Loading via script tag:
 *
 *  textfile.load({
 *    type: 'script',
 *    path: 'textfile.txt.js'
 *  })
 *    .fail(function(){
 *      console.log('an error occured!');
 *    })
 *    .done(function(res){
 *      console.log('file loaded', res);
 *    })
 *  ;
 *
 * loading via iframe:
 *
 *  textfile.load({
 *    type: 'iframe',
 *    path: 'textfile.txt'
 *  })
 *    .fail(function(){
 *      console.log('an error occured!');
 *    })
 *    .done(function(res){
 *      console.log('file loaded', res);
 *    })
 *  ;
 *
 * NOTE: When loading via a script tag, your text file must be in the
 * following format:
 */
(typeof textfile != 'undefined') && textfile.injected('NAME OF YOUR FILE', function(){/*
This is example text content
you can have as many lines as
you want.
*/});
/**
 * Once your text file is wrapped with the above the textfile code
 * will be notified that the file has been loaded, and it will also
 * allow you to have multiline text more easily in JavaScript.
 *
 * <NAME OF YOUR FILE> should be replaced with your filename to load
 * for example textfile.txt.js
 */
var textfile = (function(){

  var tf = {

    shared: {},

    create: function(config){
      return tf.prep.apply(Object.create(tf), arguments);
    },

    prep: function(config){
      this.config = config;
      this.tag = !this.config.inline
        ? document.documentElement
        : document.scripts[document.scripts.length-1]
      ;
      this.tid = setTimeout(this.bind(this.timeout), this.config.timeout || 5 * 1000);
      this.iid = setInterval(this.bind(this.polling), 100);
      this.loader = this.config.type === 'script'
        ? this.script()
        : this.frame()
      ;
      this.loader.src = this.config.path;
      !this.config.inline
        ? this.tag.appendChild(this.loader)
        : this.tag.parentNode && this.tag.parentNode.insertBefore(this.loader, null)
      ;
      return this;
    },

    script: function(element){
      if ( element ) { return element; }
      element = document.createElement('script');
      element.type = 'text/javascript';
      return element;
    },

    frame: function(element){
      if ( element ) { return element; }
      element = document.createElement('iframe');
      element.style.position = 'fixed';
      element.style.right = '100%';
      element.style.bottom = '100%';
      element.style.width = '1em';
      element.style.height = '1em';
      return element;
    },

    tidyup: function(){
      this.loader && this.loader.parentNode.removeChild(this.loader);
      return this;
    },

    loaded: function(res){
      this.trigger('done', res);
      this.tidyup();
      return this;
    },

    failed: function(){
      this.trigger('fail');
      this.tidyup();
      return this;
    },

    on: function(name, listener){
      !this.listeners && (this.listeners = {});
      !this.listeners[name] && (this.listeners[name] = []);
      this.listeners[name].push(listener);
      return this;
    },

    off: function(name, listener){
      if ( this.listeners && this.listeners[name] ) {
        for ( var a=this.listeners[name], i=a.length-1; i>=0; i-- ) {
          if ( a[i] === listener ) {
            this.listeners[name].splice(i, 1);
          }
        }
      }
      return this;
    },

    trigger: function(name, data, context){
      if ( this.listeners && this.listeners[name] ) {
        for ( var i=0, a=this.listeners[name], l=a.length; i<l; i++ ) {
          if ( a[i] && a[i].call ) {
            a[i].call( context || this, data );
          }
        }
      }
      return this;
    },

    bind: function(method, args, context){
      !context && args && !args.length && (context = args);
      !context && (context = this);
      args && (args = Array.prototype.slice.call(args));
      return function(){
        return (args
          ? method.apply(context, args.concat(Array.prototype.slice.call(arguments)))
          : method.apply(context, arguments)
        );
      };
    },

    fail: function(listener){ return this.on('fail', listener); },
    done: function(listener){ return this.on('done', listener); },

    timeout: function(){
      clearInterval(this.iid);
      this.failed();
    },

    polling: function(){
      var obj, text, ex;
      if ( this.config.type === 'iframe' ) {
        try { text = ((obj=this.loader.contentWindow) && obj.document.documentElement.textContent) ||
                     ((obj=this.loader.contentWindow) && obj.document.documentElement.innerText) ||
                     ((obj=this.loader.contentDocument) && obj.documentElement.textContent) ||
                     ((obj=this.loader.contentDocument) && obj.documentElement.innerText); 
        } catch (ex) {}
      }
      else {
        text = this.loader.textContent || 
               this.loader.text || 
               this.loader.innerHTML || 
               this.shared.loaded && this.shared.loaded[this.config.path]
        ;
      }
      if ( text && text.split ) {
        this.loaded(text);
        clearInterval(this.tid);
        clearInterval(this.iid);
      }
    },

    injected: function(script, content){
      var text = String(content && content.toString()),
          p1 = text.indexOf('/*')+2,
          p2 = text.lastIndexOf('*/')
      ;
      !this.shared.loaded && (this.shared.loaded={});
      this.shared.loaded[script] = text.substring(p1, p2);
    },

    load: function(config){
      return config && config.split
        ? tf.create({ path: config })
        : tf.create(config)
      ;
    }

  };

  return tf;

})();

答案 1 :(得分:0)

如果您已经知道文件的路径,那么只需使用onload事件调用您的函数。使用jQuery,您可以使用$(function(){});