Angular:FileReader-阅读器的访问列表

时间:2019-09-24 08:04:51

标签: angular observable filereader

我试图通过输入读取文件夹,并将包含在文件夹中的每个单独文件的内容保存在数组中。

这一切都通过此输入完成:

<div class="form-group">
        <input type="file" id="file" (change)="accessFiles($event)" webkitdirectory directory multiple >
</div>

还有这个FileReader:

files = []
readFolder(fileChangeEvent: Event) {
    this.readFile(0, (fileChangeEvent.target as HTMLInputElement).files);
 }

private readFile(index, files) {
     const reader = new FileReader();
     if (index >= files.length ) {
       console.log(this.files);
       return;
     }
     const file = files[index];
     reader.onload = (e: any) => {
       const bin = e.target.result;
       this.files.push(e.target.result);
       this.readFile(index + 1, files);
     };
       reader.readAsBinaryString(file);
}

现在,console.log中的readFile显示了数组,看起来很好,现在唯一的事情是我想稍后在代码中使用它,为此我试图返回它。 我尝试过这样的事情:

accessFiles(data){
    const contentList =  this.readDocument(data));
}

这不起作用。输出结果为undefined

我也尝试过订阅数据:

accessFiles(data){
     this.readFolder(data).subscribe(values => {
    }
}

但随后出现此错误:

  

属性'subscribe'在类型'void'上不存在。

这就是为什么我尝试实现Observable的原因:

files = []
readFolder(fileChangeEvent: Event) {
    return this.readFile(0, (fileChangeEvent.target as HTMLInputElement).files);
 }

private readFile(index, files) {
    return new Observable<any>(obs => {
     const reader = new FileReader();
     if (index >= files.length ) {
       console.log(this.files);
       obs.next({result: this.files});
       return;
     }
     const file = files[index];
     reader.onload = (e: any) => {
       const bin = e.target.result;
       this.files.push(e.target.result);
       this.readFile(index + 1, files);
     };
       reader.readAsBinaryString(file);
    });
}

但是我从中得到的唯一输出是:

  

可观察的{_isScalar:否,_subscribe:ƒ}

我不太确定这意味着什么...

如何从FileReader正确访问列表?还是我做错了什么?

1 个答案:

答案 0 :(得分:1)

最好在服务内部完成此类操作,您可以在该服务内部创建函数以在需要的任何时间获取,存储和返回文件。然后,您将该服务注入到需要此服务的组件或其他地方的构造函数中。

1。使用Angular CLI生成服务

ng generate service read-folder

这将创建一个名为read-folder.service.ts的文件,其中包含名为ReadFolderService的服务,并将其注册到您的根模块中。

2。编写服务

您真正缺少的唯一难题是FileReader的onload是异步的,并且您不能(或不应)从异步操作中同步返回值(您必须“阻止”您的应用程序在读取文件时,这是糟糕的用户体验)。相反,您应该-如您尝试的那样-从rxjs的Angular首选异步框架中使用Observables。您可以创建一个Subject并将其发送给.next(value),在等待答复的地方可以.subscribe(value => function)对其进行访问。

import { Injectable } from "@angular/core";
import { Subject } from "rxjs";

export class ReadFolderService {
  private fileCache: string[];
  private folderReader$: Subject<string[]> = new Subject();

  public readFolder(files: string[]) {
    this.fileCache = [];
    this.readFile(0, files);
    return this.folderReader$.asObservable(); // I don't return the subject itself, but a "readonly" Observable.
  }

  private readFile(index, files) {
    const reader = new FileReader();
    if (index >= files.length) {
      this.folderReader$.next(this.fileCache);
      return;
    }
    const file = files[index];
    reader.onload = (e: any) => {
      this.fileCache.push(e.target.result);
      this.readFile(index + 1, files);
    };
    reader.readAsBinaryString(file);
  }
}

3。注入服务,拨打电话并订阅其结果

在组件内部:

import { ReadFolderService } from 'src/app/read-folder.service';

...

class MyComponent {

  // Angular will inspect the arguments of your constructor and make the service for you.
  // This is called "dependency injection"
  construct(private folderReader: ReadFolderService) { }

  readFolder(fileChangeEvent: Event) {
     this.folderReader.readFolder(fileChangeEvent.target as HTMLInputElement).files)
                      .subscribe( fileContents => {
                         // Do something
                      });
  }
}

如果需要,还可以使用私有fileCache值向服务中添加另一个函数来检索最近读取的文件。但是您的递归解决方案可能会导致您在读取另一个文件夹的过程中访问fileCache。