【问题标题】:Reading file contents on the client-side in javascript in various browsers在各种浏览器中以javascript在客户端读取文件内容
【发布时间】:2010-10-19 11:59:31
【问题描述】:

我正在尝试提供一种纯脚本解决方案,用于通过浏览器读取客户端计算机上的文件内容。

我有一个适用于 Firefox 和 Internet Explorer 的解决方案。它不漂亮,但我目前只是在尝试:

function getFileContents() {
    var fileForUpload = document.forms[0].fileForUpload;
    var fileName = fileForUpload.value;

    if (fileForUpload.files) {
        var fileContents = fileForUpload.files.item(0).getAsBinary();
        document.forms[0].fileContents.innerHTML = fileContents;
    } else {
        // try the IE method
        var fileContents = ieReadFile(fileName);
        document.forms[0].fileContents.innerHTML = fileContents;
    }
}       

function ieReadFile(filename) 
{
    try
    {
        var fso  = new ActiveXObject("Scripting.FileSystemObject"); 
        var fh = fso.OpenTextFile(filename, 1); 
        var contents = fh.ReadAll(); 
        fh.Close();
        return contents;
    }
    catch (Exception)
    {
        return "Cannot open file :(";
    }
}

我可以调用getFileContents(),它会将内容写入fileContents文本区域。

有没有办法在其他浏览器中做到这一点?

目前我最关心的是 Safari 和 Chrome,但我愿意接受任何其他浏览器的建议。

编辑:回答“你为什么要这样做?”的问题:

基本上,我想在客户端将文件内容与一次性密码一起散列,以便我可以将此信息发送回作为验证。

【问题讨论】:

  • 不是我有答​​案,只是为了清楚起见,您需要知道文件的位置吗?如果不是,文件的位置是否必须从文件输入中读取,或者它可以是文本框/文本区域/其他什么?
  • 好问题。不,我并不真正关心文件的来源,只关心它的内容。使用文件输入对我来说似乎是明智的,因为它是原生 html - 我要做的事情少了。
  • 你为什么要这样做?服务器就是为了这样做。
  • 好的,简而言之:用户输入密码并选择文件。密码与文件内容一起散列,并与文件一起发送到服务器。当它到达那里时,我可以验证是否使用了正确的客户端密码。
  • 2021:let a = await file.text();

标签: javascript html file-io sandbox


【解决方案1】:

已编辑以添加有关文件 API 的信息

自从我最初写这个答案以来,File API 已被提议作为标准和implemented in most browsers(从 IE 10 开始,它增加了对此处描述的FileReader API 的支持,但还没有File API) .该 API 比旧的 Mozilla API 稍微复杂一些,因为它旨在支持文件的异步读取,更好地支持二进制文件和不同文本编码的解码。有some documentation available on the Mozilla Developer Network 以及网上的各种例子。您可以按如下方式使用它:

var file = document.getElementById("fileForUpload").files[0];
if (file) {
    var reader = new FileReader();
    reader.readAsText(file, "UTF-8");
    reader.onload = function (evt) {
        document.getElementById("fileContents").innerHTML = evt.target.result;
    }
    reader.onerror = function (evt) {
        document.getElementById("fileContents").innerHTML = "error reading file";
    }
}

原答案

在 WebKit(因此,Safari 和 Chrome)中似乎没有办法做到这一点。 File 对象拥有的唯一键是 fileNamefileSize。根据 commit message 对 File 和 FileList 的支持,它们的灵感来自 Mozilla's File object,但它们似乎只支持部分功能。

如果您想更改此设置,您可以随时 send a patch 到 WebKit 项目。另一种可能性是提议将 Mozilla API 包含在 HTML 5 中; WHATWG 邮件列表可能是最好的选择。如果你这样做,那么至少在几年内,更有可能会有一种跨浏览器的方式来做到这一点。当然,提交补丁或提案以纳入 HTML 5 确实意味着要为这个想法辩护,但 Firefox 已经实现了它的事实让你有一些开始。

【讨论】:

  • 谢谢你 - 我认为我现在还不够专注,无法提交补丁。无论如何,在您不知情的情况下,这可能是您不希望发生的事情。它有点破坏了浏览器沙箱......
  • 它不会破坏浏览器沙箱,因为您故意选择上传该文件;如果它可以到达服务器,它可以返回浏览器,只需额外的往返。考虑到使离线模式适用于网络应用程序的工作,这将是一个合理的功能。
  • 嗯,其实这是一个公平的观点。有用户交互来选择该文件。谢谢。
  • @Damovisa 我不知道你是否仍然关心这个,但我想我会更新我的答案,提到新的文件 API,它可以满足你的需求,并在Firefox、Chrome 和夜间版本的 Safari。
  • 在调用readAsText之前不应该附加事件处理程序吗?
【解决方案2】:

为了读取用户选择的文件,使用文件打开对话框,您可以使用<input type="file"> 标签。你可以找到information on it from MSDN。选择文件后,您可以使用FileReader API 读取内容。

function onFileLoad(elementId, event) {
    document.getElementById(elementId).innerText = event.target.result;
}

function onChooseFile(event, onLoadFileHandler) {
    if (typeof window.FileReader !== 'function')
        throw ("The file API isn't supported on this browser.");
    let input = event.target;
    if (!input)
        throw ("The browser does not properly implement the event object");
    if (!input.files)
        throw ("This browser does not support the `files` property of the file input.");
    if (!input.files[0])
        return undefined;
    let file = input.files[0];
    let fr = new FileReader();
    fr.onload = onLoadFileHandler;
    fr.readAsText(file);
}
<input type='file' onchange='onChooseFile(event, onFileLoad.bind(this, "contents"))' />
<p id="contents"></p>

【讨论】:

    【解决方案3】:

    有一个现代的原生替代方案:File 实现了Blob,所以我们可以调用Blob.text()

    async function readText(event) {
      const file = event.target.files.item(0)
      const text = await file.text();
      
      document.getElementById("output").innerText = text
    }
    <input type="file" onchange="readText(event)" />
    <pre id="output"></pre>

    目前(2020 年 9 月)Chrome 和 Firefox 支持此功能,对于其他浏览器,您需要加载 polyfill,例如blob-polyfill.

    【讨论】:

      【解决方案4】:

      编码愉快!
      如果您在 Internet Explorer 上遇到错误,请更改安全设置以允许 ActiveX

      var CallBackFunction = function(content) {
        alert(content);
      }
      ReadFileAllBrowsers(document.getElementById("file_upload"), CallBackFunction);
      //Tested in Mozilla Firefox browser, Chrome
      function ReadFileAllBrowsers(FileElement, CallBackFunction) {
        try {
          var file = FileElement.files[0];
          var contents_ = "";
      
          if (file) {
            var reader = new FileReader();
            reader.readAsText(file, "UTF-8");
            reader.onload = function(evt) {
              CallBackFunction(evt.target.result);
            }
            reader.onerror = function(evt) {
              alert("Error reading file");
            }
          }
        } catch (Exception) {
          var fall_back = ieReadFile(FileElement.value);
          if (fall_back != false) {
            CallBackFunction(fall_back);
          }
        }
      }
      ///Reading files with Internet Explorer
      function ieReadFile(filename) {
        try {
          var fso = new ActiveXObject("Scripting.FileSystemObject");
          var fh = fso.OpenTextFile(filename, 1);
          var contents = fh.ReadAll();
          fh.Close();
          return contents;
        } catch (Exception) {
          alert(Exception);
          return false;
        }
      }
      
      【解决方案5】:

      这很好用

      function onClick(event) {
          filecontent = "";
          var myFile = event.files[0];
          var reader = new FileReader();
      
          reader.addEventListener('load', function (e) {
            filecontent = e.target.result;
      
          });
          reader.readAsBinaryString(myFile);
        }
      

      【讨论】:

        猜你喜欢
        • 2016-02-03
        • 1970-01-01
        • 1970-01-01
        • 2011-09-16
        相关资源
        最近更新 更多