Angular: FileReader - список доступа от читателя - PullRequest
0 голосов
/ 24 сентября 2019

Я пытаюсь прочитать папку с помощью ввода и сохранить содержимое каждого отдельного файла, содержащегося в папке, в массиве.

Все это делается с помощью этого ввода:

<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 => {
    }
}

, но потом я получил эту ошибку:

Свойство «подписка» не существует для типа «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: false, _subscribe: ƒ}

Что я не совсем уверен, что это значит ...

Как можноя правильно получить доступ к списку из FileReader?или что я делаю не так?

1 Ответ

1 голос
/ 24 сентября 2019

Подобные вещи лучше всего делать внутри Службы, где вы создаете функции внутри этой службы для извлечения, хранения и возврата файлов в любое удобное для вас время.Затем вы внедряете этот Сервис в конструкторы компонентов или в другие места, где вам нужен этот сервис.

1.Создайте службу с помощью Angular CLI

ng generate service read-folder

. Это создаст файл с именем read-folder.service.ts со службой с именем ReadFolderService внутри и зарегистрирует его в корневом модуле.

2.Напишите службу

Единственная часть головоломки, которую вы действительно упустили, заключалась в том, что загрузка FileReader является асинхронной, и что вы не можете (или не должны) синхронно возвращать значение из асинхронной операции (выпришлось бы «блокировать» ваше приложение во время чтения файлов, что является плохим пользовательским опытом).Вместо этого вам следует - как вы и пытались - работать с Observables из rxjs предпочтительной асинхронной среды Angular.Вы можете создать 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, пока вы находитесь в процессе чтения другой папки.

...