58

我想读取一个文件并使用 FileReader 对象将其转换为 base64 编码的字符串。这是我使用的代码:

    var reader = new FileReader();
    reader.onloadend = 函数(evt){  
        // 文件被加载
        result_base64 = evt.target.result;
    };
    reader.readAsDataURL(文件);


但在这种情况下,我在事件处理程序(onLoadEnd 事件)中得到了转换的结果。我想要一个同步方法。有没有办法“readAsDataURL”方法可以直接返回“result_base64”变量的值?

4

6 回答 6

30

您可以使用标准FileReaderSync,它是 FileReader API 的更简单、同步、阻塞的版本,类似于您已经在使用的:

let reader = new FileReaderSync();
let result_base64 = reader.readAsDataURL(file); 

console.log(result_base64); // aGV5IHRoZXJl...

请记住,这仅在工作线程中可用,原因很明显。


如果您需要一个“读取像”同步 API 的主线程的解决方案,即顺序,您可以将异步 FileReader 包装在一个 Promise 中并使用异步函数(您可能需要转译):

async function readFileAsDataURL(file) {
    let result_base64 = await new Promise((resolve) => {
        let fileReader = new FileReader();
        fileReader.onload = (e) => resolve(fileReader.result);
        fileReader.readAsDataURL(file);
    });

    console.log(result_base64); // aGV5IHRoZXJl...

    return result_base64;
}

然后你可以在另一个异步上下文中等待这个函数:

async function main() {
    let file = new File(...)
    let dataURL = await readFileAsDataURL(file)
    console.log(dataURL); // aGV5IHRoZXJl...
}

...或者只是使用承诺回调来使用它(不需要异步上下文):

readFileAsDataURL(file).then(dataURL => {
    console.log(dataURL); // aGV5IHRoZXJl...
});
于 2019-03-13T23:05:50.543 回答
16

同步任务(阻塞)通常很糟糕。如果没有真正的理由同步执行此操作,我强烈建议您使用事件回调。

想象一下您的文件已损坏并且 HTML5 api 无法读取,它不会给您结果。它会破坏您的代码并阻止该站点。或者,有人可以选择一个 10GB 的文件,这会冻结您的 HTML 页面,直到文件完全加载。使用该异步事件处理程序,您可以捕获可能的错误。

为了解决回调的限制,我使用了一个简单的技巧:

var ready = false;
var result = '';

var check = function() {
    if (ready === true) {
         // do what you want with the result variable
         return;
    }
    setTimeout(check, 1000);
}

check();

var reader = new FileReader();
reader.onloadend = function(evt) {
    // file is loaded
    result = evt.target.result;
    
    ready = true;
};
reader.readAsDataURL(file);

检查功能,如果准备标志变量设置为真,则每秒检查一次。如果是这样,您可以确定结果是可用的。

这样做可能不是最佳实践,但我使用这种技术制作了一个 web 应用程序大约 30 次,同时运行了 10 多个 setTimeouts,直到现在都没有遇到任何问题。

于 2013-07-05T14:43:41.087 回答
1

以下代码以同步方式读取文件

 function SyncFileReader(file) {
    let self = this;
    let ready = false;
    let result = '';

    const sleep = function (ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    self.readAsArrayBuffer = async function() {
        while (ready === false) {
          await sleep(100);
        }
        return result;
    }    

    const reader = new FileReader();
    reader.onloadend = function(evt) {
        result = evt.target.result;
        ready = true;
    };
    reader.readAsArrayBuffer(file);
  }

用法 :

const fileReader = new SyncFileReader(file);
const arrayBuffer = await fileReader.readAsArrayBuffer();
于 2020-09-27T12:13:41.980 回答
-1

以下代码以同步方式读取文件并将其内容作为文本(字符串)返回

 function SyncFileReader(file) {
    let self = this;
    let ready = false;
    let result = '';

    const sleep = function (ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    self.readAsDataURL = async function() {
        while (ready === false) {
          await sleep(100);
        }
        return result;
    }    

    const reader = new FileReader();
    reader.onloadend = function(evt) {
        result = evt.target.result;
        ready = true;
    };
    reader.readAsDataURL(file);
  }

用法 :

const fileReader = new SyncFileReader(file);
const arrayBuffer = await fileReader.readAsDataURL();
于 2020-09-27T13:28:07.280 回答
-3

要同步读取文件的内容,请使用fs.readFileSync

var fs = require('fs');
var content = fs.readFileSync('myfilename');
console.log(content);

fs.createReadStream创建一个ReadStream

于 2018-11-02T14:49:15.893 回答
-4

在 Node.js 中,使用execSyncfromchild_process并让 shell 为您同步读取它。将此子进程的输出重定向到父进程。

// Don't forget to use your favorite encoding in toString()
var execSync = require('child_process').execSync;
var fileContents = execSync('cat path/to/file.txt', {stdio: "pipe"}).toString();

我很乐意接受你对 UUOC 奖的提名。;)

于 2017-04-24T22:16:26.707 回答