PrimeNG p-fileUpload上传后首次读取文件无数据问题求助
问题:PrimeNG p-fileUpload读取文件首次点击无数据,第二次才显示
你遇到的问题是点击「Show data」按钮时,第一次点击fileBuffer为空,第二次点击才能看到文件数据对吧?我来帮你分析下原因,再给出解决方案。
先看看你的核心代码片段:
HTML组件代码
<h3 class="first">Upload an excel file</h3> <p-fileUpload name="myfiles[]" chooseLabel="Choose a file" uploadLabel="Show data" cancelLabel="Cancel" accept=".csv" maxFileSize="1000000" auto="auto" customUpload="true" (uploadHandler)="myUploader($event)"> <ng-template pTemplate="toolbar"> <p-button label="Show data" icon="fa fa-upload" iconPos="left" (onClick)="myUploaderEnd($event)"></p-button> </ng-template> <ng-template pTemplate="content"> </ng-template> </p-fileUpload> <p *ngIf="datas.length > 1">{{datas[2].reference}}</p> <p>{{debug}}</p>
TypeScript组件核心代码
readFile(file: File) { var reader = new FileReader(); reader.onload = () => { this.fileBuffer+=reader.result; }; reader.readAsText(file); this.fileLines = this.fileBuffer.split("\n"); } myUploaderEnd(event) { this.readFile(this.uploadedFiles[0]); this.debug = this.uploadedFiles[0].name+"----"+this.fileBuffer; }
问题原因:FileReader是异步操作
你这里踩了一个很常见的异步操作坑:
reader.readAsText(file)是异步执行的,浏览器会在后台读取文件内容,不会阻塞后续代码的运行。- 你在调用
readAsText后立刻执行this.fileLines = this.fileBuffer.split("\n"),紧接着在myUploaderEnd里更新debug——这时候reader.onload回调还没触发,fileBuffer还是初始的空字符串,所以第一次点击看不到数据。 - 第二次点击时,第一次的文件读取已经完成,
fileBuffer已经被赋值,所以能显示出内容。
解决方案:把后续逻辑放到异步回调里,或者用Promise+async/await
方案1:直接在onload回调里处理数据
把需要用到文件内容的逻辑(比如更新debug、调用dataService)都移到reader.onload里面,确保只有当文件读取完成后才执行这些操作:
readFile(file: File) { const reader = new FileReader(); // 重置buffer,避免旧数据干扰 this.fileBuffer = ""; this.fileLines = []; reader.onload = () => { this.fileBuffer = reader.result as string; this.fileLines = this.fileBuffer.split("\n"); // 读取完成后再更新debug和处理数据 this.debug = file.name + "----" + this.fileBuffer; this.datas = this.dataService.populateDatas(this.fileLines); }; // 可选:添加错误处理 reader.onerror = () => { this.debug = `文件读取失败: ${reader.error?.message}`; }; reader.readAsText(file); } myUploaderEnd(event) { if (this.uploadedFiles.length === 0) { this.debug = "请先选择文件"; return; } this.readFile(this.uploadedFiles[0]); }
方案2:用Promise封装,配合async/await让代码更清晰
如果觉得回调嵌套不够直观,可以用Promise把FileReader包装起来,再用async/await写同步风格的代码:
// 封装FileReader为Promise readFile(file: File): Promise<string> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result as string); reader.onerror = () => reject(reader.error); reader.readAsText(file); }); } // 用async标记方法,内部可以用await async myUploaderEnd(event) { if (this.uploadedFiles.length === 0) { this.debug = "请先选择文件"; return; } try { // 等待文件读取完成 this.fileBuffer = await this.readFile(this.uploadedFiles[0]); this.fileLines = this.fileBuffer.split("\n"); this.debug = this.uploadedFiles[0].name + "----" + this.fileBuffer; this.datas = this.dataService.populateDatas(this.fileLines); } catch (error) { this.debug = `文件读取失败: ${(error as Error).message}`; } }
这样修改后,第一次点击「Show data」按钮就能直接读取并显示文件内容了,不用再点第二次~
内容的提问来源于stack exchange,提问作者L. Quastana
相关产品推荐
相关产品推荐

