如何在浏览器中读取本地文本文件?

533

我正在尝试通过创建一个函数来实现一个简单的文本文件阅读器,该函数接受文件路径并将每行文本转换为字符数组,但它不起作用。

function readTextFile() {
  var rawFile = new XMLHttpRequest();
  rawFile.open("GET", "testing.txt", true);
  rawFile.onreadystatechange = function() {
    if (rawFile.readyState === 4) {
      var allText = rawFile.responseText;
      document.getElementById("textSection").innerHTML = allText;
    }
  }
  rawFile.send();
}

这里出了什么问题?

在从以前的修订版稍微更改代码后,仍然似乎无法正常工作,现在它给我一个XMLHttpRequest异常101。

我已在Firefox上测试过,它可以正常工作,但在Google Chrome上它只是不起作用,并且一直给我Exception 101。我如何使它不仅在Firefox上工作,而且在其他浏览器上(特别是Chrome)也能正常工作?


具体发生了什么?数组里面是空的吗?还是只有“错误”的东西...? - PinkElephantsOnParade
你是在本地机器上进行测试吗?请确保测试 status0200 - Jeffrey Sweeney
1
@JeffreySweeney 是的,我正在本地机器上测试这个。我已经将文本文件存储在与JavaScript和HTML相同的位置。 - Danny
24个回答

400

JS 在2015年引入了Fetch API,该API用于替换XMLHttpRequest,以更简单的方式从URL获取数据。在这种情况下:

fetch("myText.txt")
  .then((res) => res.text())
  .then((text) => {
    // do something with "text"
   })
  .catch((e) => console.error(e));

由于现代浏览器严格限制直接文件系统访问的操作,所以请尽量不要使用file:///。即使你只是在本地工作,也有很多轻量级的Web服务器可供使用(包括运行python -m http.servernpx http-server等),这样你就可以使用正常的http URL加载数据。
需要检查状态0(因为在使用XMLHttpRequest本地加载文件时,没有返回状态,因为它不是来自Webserver
function readTextFile(file) {
  var rawFile = new XMLHttpRequest();
  rawFile.open("GET", file, false);
  rawFile.onreadystatechange = function () {
    if(rawFile.readyState === 4)  {
      if(rawFile.status === 200 || rawFile.status == 0) {
        var allText = rawFile.responseText;
        console.log(allText);
       }
    }
  }
  rawFile.send(null);
}

并在文件名中指定file://

readTextFile("file:///C:/your/path/to/file.txt");

4
我实际上正在使用 Mac 进行这项工作,所以我是否仍需要指定 file://? - Danny
18
请尝试将file:///User/Danny/Desktop/javascriptWork/testing.txt输入到您浏览器的地址栏中,查看是否能够看到该文件。 - Majid Laissi
24
没必要使用绝对路径,以下方式适用于我:readTextFile('Properties/version.txt'); 谢谢! - Sonic Soul
203
这在Chrome中无法运行(可能在其他浏览器也是如此),您会收到一个错误信息:“跨源请求只支持以下协议方案:http、data、chrome、chrome-extension、https和chrome-extension-resource。” - Rick Burgess
3
这真的可以在没有用户交互的情况下运行吗?我无法让它在 Chrome 中工作(除非用户选择文件)。 - Xan-Kun Clark-Davis
显示剩余26条评论

200
在JavaScript中引入fetch api后,读取文件内容变得非常简单。 读取文本文件
fetch('file.txt')
  .then(response => response.text())
  .then(text => console.log(text))
  // outputs the content of the text file

读取一个 JSON 文件。
fetch('file.json')
  .then(response => response.json())
  .then(jsonResponse => console.log(jsonResponse))     
   // outputs a javascript object from the parsed json

2018年7月30日更新(免责声明):

这种技术在Firefox中运行良好,但似乎Chromefetch实现不支持file:/// URL方案,截至本次更新的日期(在Chrome 68中测试)。

更新-2(免责声明):

由于相同的(安全)原因,此技术在Firefox 68以上版本(2019年7月9日)无法使用: CORS请求不是HTTP。请参见https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp


4
太棒了!引用Fetch标准:“提供了统一的处理方式:URL方案、重定向、跨源语义、CSP、Service workers、混合内容和引用”。我猜这意味着我们要和旧有的FileReaders和HttpRequests说再见了(我一点也不会想念它们 ;))。 - Armfoot
3
但是你如何将这个“文本”放入字符串变量中以便在其他地方使用?(无论我怎么做,它总是显示“未定义”)。 - not2qubit
2
@not2qubit,获取文本文件是异步操作。您得到undefined是因为在文件完全读取之前使用了变量。您必须在promise回调中使用它或使用类似JavaScript的“async await”运算符。 - Abdelaziz Mokhnache
40
Fetch API 无法加载 file:///C:/Users/path/to/file/file.txt。 CORS 请求的 URL 方案必须为 "http" 或 "https"。 - J-Cake
2
同样的问题,愚蠢的Chrome 68。我简直不敢相信这是一个热门话题,感谢@AbdelazizMokhnache让我们保持了解。JAK。我刚刚测试了File-Save.js,它可以工作,我想要一个简单的方法来读取文件(基本上是将我的设置保存/恢复到我选择的文件中)。 - Meryan
显示剩余6条评论

140

访问 Javascripture!并转到readAsText部分,尝试示例。您将能够了解FileReaderreadAsText函数如何工作。

var openFile = function(event) {
  var input = event.target;

  var reader = new FileReader();
  reader.onload = function() {
    var text = reader.result;
    var node = document.getElementById('output');
    node.innerText = text;
    console.log(reader.result.substring(0, 200));
  };
  reader.readAsText(input.files[0]);
};
<input type='file' accept='text/plain' onchange='openFile(event)'><br>
<div id='output'>
  ...
</div>


21
链接很好,但你应该“引用重要链接中最相关的部分,以防目标站点无法访问或永久下线。”请参见如何撰写好答案 - 4ae1e1
26
这个示例涉及用户输入的文本文件,但我认为问题是关于服务器本地文件的。 - S. Kirby
3
正如原帖对于本地运行和远程服务器的问题回答所述:一切都是本地的,都在一个文件夹中没有其他东西。 此外,其他人(比如我)可能会有关于如何在本地运行的问题。 - Simon Forsberg
这个解决方案会自动读取所选文件的内容,我很喜欢它。我想让它像 urltodomain.com(在一个文本区域中)一样工作,但最初失败了,因为这个:node.innerText = text;(脚本将内容填充到了 <textarea> 标签中,而不是将其添加到文本区域中)。为了使其工作,我将其替换为:node.value = text; - Tomasz

57

var input = document.getElementById("myFile");
var output = document.getElementById("output");


input.addEventListener("change", function () {
  if (this.files && this.files[0]) {
    var myFile = this.files[0];
    var reader = new FileReader();
    
    reader.addEventListener('load', function (e) {
      output.textContent = e.target.result;
    });
    
    reader.readAsBinaryString(myFile);
  }   
});
<input type="file" id="myFile">
<hr>
<textarea style="width:500px;height: 400px" id="output"></textarea>


20
我不确定这个回答是否能解决这个四年前的问题。楼主没有上传文件,他们正在尝试从路径中读取相同目录下的文本文件。如果您要回答这么旧的问题,至少写一个简短的摘要,说明为什么您认为您的答案现在比其他答案更好,或者自问题以来语言发生了什么变化,需要新的回答。 - Matthew Ciaramitaro
4
使用我自己现有的文件上传输入HTML,复制从var reader = new FileReader();reader.readAsBinaryString(..)的代码行 - 它将读取我的文本文件内容。简洁优雅,非常好用。对我来说这是该主题下最好的答案-谢谢! - Gene Bo
如何获取文件名? - Random Kindle

39

现代解决方案:

使用fileOrBlob.text(),如下所示:

<input type="file" onchange="this.files[0].text().then(t => console.log(t))">

当用户通过输入上传文本文件时,该文件将被记录在控制台中。这里是一个可以工作的 jsbin 演示
以下是更详细的说明:
<input type="file" onchange="loadFile(this.files[0])">
<script>
  async function loadFile(file) {
    let text = await file.text();
    console.log(text);
  }
</script>

目前(2020年1月),此功能仅适用于Chrome和Firefox浏览器,如果您在未来阅读此内容,请检查兼容性:https://developer.mozilla.org/en-US/docs/Web/API/Blob/text

在旧版浏览器上,可以使用以下方法:

<input type="file" onchange="loadFile(this.files[0])">
<script>
  async function loadFile(file) {
    let text = await (new Response(file)).text();
    console.log(text);
  }
</script>

相关信息:截至2020年9月,Chrome和Edge浏览器推出了新的本地文件系统API,以便您永久性地读取(甚至写入)用户选择的文件。


什么是路径根? - mathtick
1
你需要在示例中创建Blob,否则我认为这对人们来说没有用。 - mathtick

36

是的,JavaScript可以读取本地文件(参见FileReader()),但不能自动完成:用户必须通过html <input type="file"> 将文件或文件列表传递给脚本。

然后,使用JS可以处理(例如查看)文件或文件列表、它们的某些属性以及文件或文件内容。

出于安全原因,JS无法自动访问(无需用户输入)他的计算机文件系统。

要允许JS自动访问本地fs,需要创建一个hta文档而不是包含JS的html文件。

hta文件中可以包含JS或VBS。

但是,hta可执行文件仅适用于Windows系统。

这是标准浏览器行为。

Google Chrome还使用了fs API,更多信息请参见:http://www.html5rocks.com/en/tutorials/file/filesystem/


17

使用Fetch和异步函数

const logFileText = async file => {
    const response = await fetch(file)
    const text = await response.text()
    console.log(text)
}

logFileText('file.txt')

19
我得到了“跨域请求的URL方案必须是“http”或“https”。”的错误提示。 - Qwerty
完美的解决方案。就像“logFileText('./test.txt')”一样简单。 - Amit

12

尝试创建两个函数:

function getData(){       //this will read file and send information to other function
       var xmlhttp;

       if (window.XMLHttpRequest) {
           xmlhttp = new XMLHttpRequest();               
       }           
       else {               
           xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");               
       }

       xmlhttp.onreadystatechange = function () {               
           if (xmlhttp.readyState == 4) {                   
             var lines = xmlhttp.responseText;    //*here we get all lines from text file*

             intoArray(lines);     *//here we call function with parameter "lines*"                   
           }               
       }

       xmlhttp.open("GET", "motsim1.txt", true);
       xmlhttp.send();    
}

function intoArray (lines) {
   // splitting all text data into array "\n" is splitting data from each new line
   //and saving each new line as each element*

   var lineArr = lines.split('\n'); 

   //just to check if it works output lineArr[index] as below
   document.write(lineArr[2]);         
   document.write(lineArr[3]);
}

这个适用于哪些浏览器(似乎有6个人尝试过 :-) )? - Xan-Kun Clark-Davis

12
也许你已经尝试过了,但请按照以下方式键入"false":
     rawFile.open("GET", file, false);

11

另一个例子 - 使用FileReader类的我的读取器

<html>
    <head>
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css">
        <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
        <script src="http://code.jquery.com/ui/1.11.3/jquery-ui.js"></script>
    </head>
    <body>
        <script>
            function PreviewText() {
            var oFReader = new FileReader();
            oFReader.readAsDataURL(document.getElementById("uploadText").files[0]);
            oFReader.onload = function (oFREvent) {
                document.getElementById("uploadTextValue").value = oFREvent.target.result; 
                document.getElementById("obj").data = oFREvent.target.result;
            };
        };
        jQuery(document).ready(function(){
            $('#viewSource').click(function ()
            {
                var text = $('#uploadTextValue').val();
                alert(text);
                //here ajax
            });
        });
        </script>
        <object width="100%" height="400" data="" id="obj"></object>
        <div>
            <input type="hidden" id="uploadTextValue" name="uploadTextValue" value="" />
            <input id="uploadText" style="width:120px" type="file" size="10"  onchange="PreviewText();" />
        </div>
        <a href="#" id="viewSource">Source file</a>
    </body>
</html>

2
文件返回 base64 输出 - V.P.

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