Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 与可观测数据并行读取文件_Angular_Typescript_Rxjs5 - Fatal编程技术网

Angular 与可观测数据并行读取文件

Angular 与可观测数据并行读取文件,angular,typescript,rxjs5,Angular,Typescript,Rxjs5,我正在编写一些应用程序来读取用户选择的文件并将其转换为base64。我想在内存中读取所有文件时收到通知。为此,我使用Observable来处理FileReader的onload事件,并发送完整的通知。我正在使用forkJoin并行运行该操作 请看下面的代码,我正在创建Observable并订阅它 onChange($event: any) { console.log('No of files selected: ' + $event.target.files.length); var o

我正在编写一些应用程序来读取用户选择的文件并将其转换为base64。我想在内存中读取所有文件时收到通知。为此,我使用
Observable
来处理
FileReader
onload
事件,并发送完整的通知。我正在使用
forkJoin
并行运行该操作

请看下面的代码,我正在创建
Observable
并订阅它

onChange($event: any) {
  console.log('No of files selected: ' + $event.target.files.length);
  var observableBatch : any = [];

  var rawFiles = $event.target.files;
  for (var i = rawFiles.length - 1; i >= 0; i--) {

      var reader = new FileReader(); 
      var file = rawFiles[i];
      var myobservable = Observable.create((observer: any) => {
        reader.onload = function (e: any) {
          var data = e.target;
          var imageSrc = data.result;
          console.log('File loaded succesfully.' );
          observer.next("File loaded");
          observer.complete();
        };
       });

      observableBatch.push(myobservable);
      reader.readAsArrayBuffer(file);

  }

  Observable.forkJoin(observableBatch)
  .subscribe(
      (m) => {
        console.log(m);
      },
      (e) => {
        console.log(e);
      },
      () => {
        console.log("All file(s) loading completed!!!");
      }
    ); 
}
完整的示例代码在中提供

当我选择一个文件时,会执行
onload
函数,并获得以下控制台日志

但是,当我选择多个文件时,
onload
只执行一次,批处理操作没有完成。请参阅以下控制台日志

有人能帮我理解我犯了什么错误吗?

我从一个类似的问题中找到了答案。显然,这与循环和回调的运行顺序有关。我认为,
.forkJoin()
正在等待传递给它的所有可观察对象完成,但当它获得所有可观察对象并订阅时,第一次onload已经完成,因此可观察到的完成永远不会发生

无论如何,您可以通过将设置FileReader、Observable和onload回调的代码放入它自己的函数中来解决这个问题


我使用flatmap来确保加载了所有内容

import {Injectable} from '@angular/core'
import {Attachment} from './attachments.component'
import {Inject} from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject'
import {Observable} from "rxjs/Observable";
import {AttachmentBackendService} from './attachment.backend.service'
import 'rxjs/add/observable/from'
import 'rxjs/add/operator/mergeMap'

@Injectable()
export class AttachmentStore {
  private _attachments: BehaviorSubject<Attachment[]> = new     BehaviorSubject<Attachment[]>([])
  private dataStore : {
    attachments : Attachment[]
  }
  private storeId : string = ''
  private attachmentId : number = 0

  constructor(private attachmentBackendService: AttachmentBackendService) {
    this.dataStore = { attachments : [] }
  }

  get attachments() {
    return this._attachments.asObservable()
  }

  // public
  addFiles(files: FileList) {
    let fileArray = Array.from(files)
    this.processFiles(
         fileArray[0],
         fileArray.slice(1))
       .subscribe(
         (attachment) => {
           this.storeAndSaveAttachment(attachment)
           this._attachments.next(this.dataStore.attachments)
         },
         (e) => {
           console.log(e)
         },
         () => {
           console.log("file loading completed!!!")
         })
   return this.storeId
 }

 removeFile(index: number) {
   let attachment = this.dataStore.attachments[index]
   this.attachmentBackendService.deleteAttachment(this.storeId, attachment.id)
   this.dataStore.attachments.splice(index, 1)
   this._attachments.next(this.dataStore.attachments)
 }

 // private
 private processFiles(file : File, fileArray : File[]) {
   if (fileArray.length > 0) {
     return this.processFiles(
                   fileArray.slice(0,1)[0],
                   fileArray.slice(1))
                .flatMap( (attachment) => {
                  this.storeAndSaveAttachment(attachment)
                  return this.fileReaderObs(file,this.attachmentId++)
                })
   } else {
     if (this.storeId == '')
     {
       this.storeId = this.attachmentBackendService.storeId
     }
     return this.fileReaderObs(file,this.attachmentId++)
   }
 }

 private storeAndSaveAttachment(attachment : Attachment) {
   this.dataStore.attachments.push(attachment)
   this.attachmentBackendService.saveAttachment(this.storeId, attachment)
 }

 private fileReaderObs(file : File, attachmentId : number)  {
   let reader = new FileReader()
   let fileReaderObs = Observable.create((observer: any) => {
     reader.onload = function() {
       let attachment : Attachment = {
         id : attachmentId,
         name : file.name,
         data : btoa(reader.result)
       }
       observer.next(attachment)
       observer.complete()
     }
   })
   reader.readAsBinaryString(file)
   return fileReaderObs
 }
从'@angular/core'导入{Injectable}
从“./attachments.component”导入{Attachment}
从“@angular/core”导入{Inject}
从'rxjs/BehaviorSubject'导入{BehaviorSubject}
从“rxjs/Observable”导入{Observable};
从“./attachment.backend.service”导入{AttachmentBackendService}
导入“rxjs/add/observable/from”
导入“rxjs/add/operator/mergeMap”
@可注射()
导出类附件存储{
私有_附件:BehaviorSubject=新的BehaviorSubject([])
专用数据存储:{
附件:附件[]
}
私有存储ID:字符串=“”
私有附件ID:编号=0
构造函数(私有attachmentBackendService:attachmentBackendService){
this.dataStore={attachments:[]}
}
获取附件(){
返回此。\u attachments.asObservable()
}
//公开的
添加文件(文件:文件列表){
让fileArray=Array.from(文件)
此文件为.processFiles(
fileArray[0],
fileArray.slice(1))
.订阅(
(附件)=>{
此.storeAndSaveAttachment(附件)
this.\u attachments.next(this.dataStore.attachments)
},
(e) =>{
控制台日志(e)
},
() => {
console.log(“文件加载完成!!!”)
})
返回此.storeId
}
removeFile(索引:编号){
让attachment=this.dataStore.attachments[index]
this.attachmentBackendService.deleteAttachment(this.storeId,attachment.id)
this.dataStore.attachments.splice(索引,1)
this.\u attachments.next(this.dataStore.attachments)
}
//私人的
私有进程文件(文件:文件,文件数组:文件[]){
如果(fileArray.length>0){
返回此.processFiles(
fileArray.slice(0,1)[0],
fileArray.slice(1))
.flatMap((附件)=>{
此.storeAndSaveAttachment(附件)
返回此.fileReaderObs(文件,this.attachmentId++)
})
}否则{
if(this.storeId=='')
{
this.storeId=this.attachmentBackendService.storeId
}
返回此.fileReaderObs(文件,this.attachmentId++)
}
}
private storeAndSaveAttachment(附件:附件){
this.dataStore.attachments.push(附件)
this.attachmentBackendService.saveAttachment(this.storeId,附件)
}
私有文件阅读器(文件:file,附件ID:number){
let reader=new FileReader()
让fileReaderObs=Observable.create((observator:any)=>{
reader.onload=函数(){
让附件:附件={
id:attachmentId,
name:file.name,
数据:btoa(reader.result)
}
下一位观察员(附件)
观察员:完成()
}
})
reader.readAsBinaryString(文件)
返回文件读取器
}

}我想提出这个解决方案。如果这个解决方案有问题,请随时告诉我

const files=Array.from(event.srcielement.files);
可观察。从(文件)
.map((文件:file)=>{
const reader=new FileReader();
const load$=Observable.fromEvent(读取器,'load')。取(1);
const read$=Observable.of(file).do(reader.readAsDataURL.bind(reader));
返回[load$,read$];
})
.toArray()
.switchMap((值:任意)=>{
const arrayObservables=值。reduce((acc,value)=>acc.concat(value),[]);
返回可观察的forkJoin(…arrayObservables);
})
.订阅({
下一步:console.log

});-1表示非标准的readAsBinaryString,-1表示不处理错误,-1表示有状态处理,-1表示使用subscribe而不是mergeMap或类似。。。等等,我确实让你知道了你的错误。但是我没有给你-1分,因为你已经尽力了;)。需要对您的答案进行太多更改,以使其成为生产质量代码,以便我对其进行评论或更正。新的FileReader(文件)不正确,因为FileReader不使用参数进行实例化。
import {Injectable} from '@angular/core'
import {Attachment} from './attachments.component'
import {Inject} from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject'
import {Observable} from "rxjs/Observable";
import {AttachmentBackendService} from './attachment.backend.service'
import 'rxjs/add/observable/from'
import 'rxjs/add/operator/mergeMap'

@Injectable()
export class AttachmentStore {
  private _attachments: BehaviorSubject<Attachment[]> = new     BehaviorSubject<Attachment[]>([])
  private dataStore : {
    attachments : Attachment[]
  }
  private storeId : string = ''
  private attachmentId : number = 0

  constructor(private attachmentBackendService: AttachmentBackendService) {
    this.dataStore = { attachments : [] }
  }

  get attachments() {
    return this._attachments.asObservable()
  }

  // public
  addFiles(files: FileList) {
    let fileArray = Array.from(files)
    this.processFiles(
         fileArray[0],
         fileArray.slice(1))
       .subscribe(
         (attachment) => {
           this.storeAndSaveAttachment(attachment)
           this._attachments.next(this.dataStore.attachments)
         },
         (e) => {
           console.log(e)
         },
         () => {
           console.log("file loading completed!!!")
         })
   return this.storeId
 }

 removeFile(index: number) {
   let attachment = this.dataStore.attachments[index]
   this.attachmentBackendService.deleteAttachment(this.storeId, attachment.id)
   this.dataStore.attachments.splice(index, 1)
   this._attachments.next(this.dataStore.attachments)
 }

 // private
 private processFiles(file : File, fileArray : File[]) {
   if (fileArray.length > 0) {
     return this.processFiles(
                   fileArray.slice(0,1)[0],
                   fileArray.slice(1))
                .flatMap( (attachment) => {
                  this.storeAndSaveAttachment(attachment)
                  return this.fileReaderObs(file,this.attachmentId++)
                })
   } else {
     if (this.storeId == '')
     {
       this.storeId = this.attachmentBackendService.storeId
     }
     return this.fileReaderObs(file,this.attachmentId++)
   }
 }

 private storeAndSaveAttachment(attachment : Attachment) {
   this.dataStore.attachments.push(attachment)
   this.attachmentBackendService.saveAttachment(this.storeId, attachment)
 }

 private fileReaderObs(file : File, attachmentId : number)  {
   let reader = new FileReader()
   let fileReaderObs = Observable.create((observer: any) => {
     reader.onload = function() {
       let attachment : Attachment = {
         id : attachmentId,
         name : file.name,
         data : btoa(reader.result)
       }
       observer.next(attachment)
       observer.complete()
     }
   })
   reader.readAsBinaryString(file)
   return fileReaderObs
 }