在各种浏览器中使用JavaScript读取客户端文件内容

176

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

我有一个在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,但我也愿意听取对其他浏览器的建议。

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

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


我并没有答案,但为了澄清,您需要知道文件的位置吗?如果不需要,那么文件的位置是否必须从文件输入中读取,或者可以是文本框/文本区域/任何其他形式的输入? - Darko
好问题。不,我并不真的关心文件来自哪里,只关心它的内容。使用文件输入似乎对我来说很合理,因为它是本地HTML——这样我就少做了一件事情。 - Damovisa
你为什么要这样做呢?服务器本来就是用来处理这个的。 - geowa4
好的,简而言之:用户输入密码并选择文件。密码与文件内容进行哈希处理,随后将其与文件一起发送到服务器。到达服务器时,我可以验证是否使用了正确的客户端密码。 - Damovisa
1
2021年:let a = await file.text(); - Harshal Parekh
5个回答

237

添加了有关File API的信息

自原作者撰写此答案后,File API已被提议为标准,并在大多数浏览器中实现(自IE 10起,添加了对本文所述的FileReader API的支持,但尚未实现File API)。该API比较复杂,旨在支持异步读取文件、更好地支持二进制文件和解码不同的文本编码。在Mozilla开发者网络上有一些文档,并且还有各种在线示例。您可以按照以下方式使用它:

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";
    }
}

Translated answer

在WebKit中(因此,在Safari和Chrome中)似乎没有办法做到这一点。 File对象具有的唯一键是fileNamefileSize。 根据支持File和FileList的提交消息,这些受到Mozilla's File object启发,但它们似乎仅支持一部分功能。

如果您想更改此设置,您可以随时向WebKit项目发送补丁。 另一个可能性是提议将Mozilla API纳入HTML 5; WHATWG邮件列表可能是这样做的最佳场所。 如果您这样做,则至少在几年内可能会有一种跨浏览器的方法来实现此操作。 当然,提交补丁或将建议纳入HTML 5也意味着要花费一些时间来捍卫这个想法,但Firefox已经实现了这个功能,这让您有了一个起点。


5
如果您有意上传该文件,则它不会破坏浏览器沙盒;如果它能够到达服务器,则可以通过额外的往返传回浏览器。考虑到为Web应用程序使离线模式正常工作所做的工作,这将是一个合理的功能。 - Brian Campbell
1
@Damovisa 不知道你是否还关注这个问题,但我想更新我的回答,提到新的文件API,它实现了你所需要的功能,在Firefox、Chrome和Safari的夜间版本中已经实现。 - Brian Campbell
太好了!FileReader正常工作!在FireFox、MS Edge和MS Internet Explorer下进行了测试。 - José Carlos PHP
2
在调用readAsText之前,事件处理程序不应该被附加吗? - goofballLogic
我可以确认,在调用readAsText之前必须先附加事件处理程序! - BenMorel
显示剩余4条评论

35

现在有一种现代原生的替代方法: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支持此功能,对于其他浏览器,您需要加载一个兼容库,例如blob-polyfill


2
现在所有主要的浏览器都支持这个功能 - https://caniuse.com/mdn-api_blob_text - Jimmy

33
为了读取用户选择的文件,可以使用文件打开对话框和 <input type="file"> 标签。你可以从 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>


5

愉快的编码!
如果在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;
  }
}

9
ActiveX现在已经(令人欣慰地)不再使用了。 - Liam

2

这个运行正常

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);
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接