使用 formData() 上传多个文件

Posted

技术标签:

【中文标题】使用 formData() 上传多个文件【英文标题】:Uploading multiple files using formData() 【发布时间】:2012-10-10 23:09:22 【问题描述】:
var fd = new FormData();
fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
var xhr = new XMLHttpRequest();
xhr.open("POST", "uph.php");
xhr.send(fd);

uph.php:

var_dump($_FILES['fileToUpload']);

这有效,但显然仅适用于files[0]。如何使它适用于所选文件?

我尝试删除[0],但没有成功。

【问题讨论】:

【参考方案1】:

您只需要使用fileToUpload[] 而不是fileToUpload

fd.append("fileToUpload[]", document.getElementById('fileToUpload').files[0]);

它会返回一个包含多个名称、大小等的数组...

【讨论】:

这需要循环,并附加每个files[i]【参考方案2】:

您必须获取文件长度以附加到 JS 中,然后通过 AJAX 请求发送,如下所示

//javascript 
var ins = document.getElementById('fileToUpload').files.length;
for (var x = 0; x < ins; x++) 
    fd.append("fileToUpload[]", document.getElementById('fileToUpload').files[x]);


//PHP
$count = count($_FILES['fileToUpload']['name']);
for ($i = 0; $i < $count; $i++) 
    echo 'Name: '.$_FILES['fileToUpload']['name'][$i].'<br/>';

【讨论】:

对我不起作用。我想这取决于您的多部分表单将如何处理服务器端。 According to MDN As with regular form data, you can append multiple values with the same name. For example (and being compatible with PHP's naming conventions by adding [] to the name):. See Example 3@Phoenix 只返回一个文件 fileToUpload[] 错了,应该是fileToUpload @HoussemBadri 在我的情况下 fileToUpload 不起作用。正如答案中所建议的那样,它应该是fileToUpload[]。你的评论花了我一个小时才弄清楚发生了什么。【参考方案3】:

使用 javascript 的方法:

var data = new FormData();

$.each($("input[type='file']")[0].files, function(i, file) 
    data.append('file', file);
);

$.ajax(
    type: 'POST',
    url: '/your/url',
    cache: false,
    contentType: false,
    processData: false,
    data : data,
    success: function(result)
        console.log(result);
    ,
    error: function(err)
        console.log(err);
    
)

如果您多次调用 data.append('file', file),您的请求将包含您的文件数组。

From MDN web docs:

FormData 接口的append() 方法将一个新值附加到FormData 对象内的现有键上,如果该键不存在,则添加该键。 FormData.set 和 append() 之间的区别在于,如果指定的键已经存在,FormData.set 将用新的值覆盖所有现有值,而 append() 会将新值附加到现有值集的结尾。”

我自己使用node.js和multipart handler中间件multer获取数据如下:

router.post('/trip/save', upload.array('file', 10), function(req, res)
    // Your array of files is in req.files

【讨论】:

...If you call data.append('file', file) multiple times your request will contain an array of your files... 救了我几个小时的绝望,特别是因为我觉得名字应该是file[],但只使用file 并多次调用有效,谢谢! 老兄,你是个传奇,从早上开始就一直在寻找这个,谢谢分配人 我试过你的例子,但是当我 var_dumped 它时,它总是返回集合的最后一个图像。我将:data.append('file', file) 更改为 data.append('file', i),这对我有用。 你是我的英雄 这一行是最重要的信息If you call data.append('file', file) multiple times your request will contain an array of your files. 非常感谢。节省了我数小时的时间。【参考方案4】:

这很好用!

var fd = new FormData();

$('input[type="file"]').on('change', function (e) 
    [].forEach.call(this.files, function (file) 
        fd.append('filename[]', file);
    );
);

$.ajax(
    url: '/url/to/post/on',
    method: 'post',
    data: fd,
    contentType: false,
    processData: false,
    success: function (response) 
        console.log(response)
    ,
    error: function (err) 
        console.log(err);
    
);

【讨论】:

在你的代码中添加一个简短的解释将会得到一个更好的答案!只是一个有用的提示【参考方案5】:

这对我有用:

let formData = new FormData()
formData.append('files', file1)
formData.append('files', file2)

【讨论】:

文件必须在循环中追加。【参考方案6】:

这个对我有用

//Javascript part
//file_input is a file input id
var formData = new FormData();
var filesLength=document.getElementById('file_input').files.length;
for(var i=0;i<filesLength;i++)
	formData.append("file[]", document.getElementById('file_input').files[i]);

$.ajax(
   url: 'upload.php',
   type: 'POST',
   data: formData,
   contentType: false,
   cache: false,
   processData: false,
   success: function (html) 
   
  
);

<?php
//PHP part
$file_names = $_FILES["file"]["name"];
for ($i = 0; $i < count($file_names); $i++) 
   $file_name=$file_names[$i];
   $extension = end(explode(".", $file_name));
   $original_file_name = pathinfo($file_name, PATHINFO_FILENAME);
   $file_url = $original_file_name . "-" . date("YmdHis") . "." . $extension;
 move_uploaded_file($_FILES["file"]["tmp_name"][$i], $absolute_destination . $file_url);

【讨论】:

【参考方案7】:

这是针对此问题的 Vanilla JavaScript 解决方案 -

首先,我们将使用Array.prototype.forEach() 方法,如

document.querySelectorAll('input[type=file]') 返回一个类似对象的数组

然后我们将使用Function.prototype.call() 方法将类数组对象 中的每个元素分配给.forEach 方法中的this 值。

HTML

<form id="myForm">

    <input type="file" name="myFile" id="myFile_1">
    <input type="file" name="myFile" id="myFile_2">
    <input type="file" name="myFile" id="myFile_3">

    <button type="button" onclick="saveData()">Save</button>

</form>

JavaScript

 function saveData()
     var data = new FormData(document.getElementById("myForm"));
     var inputs = document.querySelectorAll('input[type=file]');

     Array.prototype.forEach.call(inputs[0].files, function(index)
        data.append('files', index);
     );
     console.log(data.getAll("myFile"));

您可以查看同一HERE的工作示例

【讨论】:

【参考方案8】:

创建一个FormData 对象

const formData: any = new FormData();

并附加到相同的 keyName

photos.forEach((_photoInfo:  localUri: string, file: File ) => 
    formData.append("file", _photoInfo.file);
);

并将其发送到服务器

// angular code
this.http.post(url, formData)

这将自动在file下创建一个对象数组

如果你使用的是 nodejs

const files :File[] = req.files ? req.files.file : null;

【讨论】:

【参考方案9】:

我为我找到了这份工作!

var fd = new FormData();
$.each($('.modal-banner [type=file]'), function(index, file) 
  fd.append('item[]', $('input[type=file]')[index].files[0]);
);

$.ajax(
  type: 'POST',
  url: 'your/path/', 
  data: fd,
  dataType: 'json',
  contentType: false,
  processData: false,
  cache: false,
  success: function (response) 
    console.log(response);
  ,
  error: function(err)
    console.log(err);
  
).done(function() 
  // do something....
);
return false;

【讨论】:

请为您的答案添加更多解释【参考方案10】:

要上传多个带有角度表单数据的文件,请确保您的 component.html 中有此文件

上传文件

                <div class="row">


                  <div class="col-md-4">
                     &nbsp; <small class="text-center">  Driver  Photo</small>
                    <div class="form-group">
                      <input  (change)="onFileSelected($event, 'profilepic')"  type="file" class="form-control" >
                    </div>
                  </div>

                  <div class="col-md-4">
                     &nbsp; <small> Driver ID</small>
                    <div class="form-group">
                      <input  (change)="onFileSelected($event, 'id')"  type="file" class="form-control" >
                    </div>
                  </div>

                  <div class="col-md-4">
                    &nbsp; <small>Driving Permit</small>
                    <div class="form-group">
                      <input type="file"  (change)="onFileSelected($event, 'drivingpermit')" class="form-control"  />
                    </div>
                  </div>
                </div>



                <div class="row">
                    <div class="col-md-6">
                       &nbsp; <small>Car Registration</small>
                      <div class="form-group">
                        <div class="input-group mb-4">
                            <input class="form-control" 
                (change)="onFileSelected($event, 'carregistration')" type="file"> <br>
                        </div>
                      </div>
                    </div>

                    <div class="col-md-6">
                        <small id="li"> Car Insurance</small>
                      <div class="form-group">
                        <div class="input-group mb-4">
                          <input class="form-control" (change)="onFileSelected($event, 

                         'insurancedocs')"   type="file">
                        </div>
                      </div>
                    </div>

                  </div>


                <div style="align-items:c" class="modal-footer">
                    <button type="button" class="btn btn-secondary" data- 
                  dismiss="modal">Close</button>
                    <button class="btn btn-primary"  (click)="uploadFiles()">Upload 
                  Files</button>
                  </div>
              </form>

在您的 componenet.ts 文件中 像这样声明数组选择的文件

selectedFiles = [];

// 所选文件的数组

onFileSelected(event, type) 
    this.selectedFiles.push( type, file: event.target.files[0] );
  

//在上传文件方法中,像这样附加你的表单数据

uploadFiles() 
    const formData = new FormData(); 

    this.selectedFiles.forEach(file => 
      formData.append(file.type, file.file, file.file.name); 
    );
    formData.append("driverid", this.driverid);

    this.driverService.uploadDriverDetails(formData).subscribe(
      res => 
        console.log(res); 

      ,
      error => console.log(error.message)
    );
  

注意:我希望这个解决方案对你的朋友有用

【讨论】:

【参考方案11】:

在附加到 fd 时添加 [] 有效,但如果您希望将数据按文件分组,那么我建议您这样做:

var files= document.getElementById('inpFile').files
var fd = new FormData()

for (let i = 0; i < files.length; i++) 
  fd.append(i, files[i])

现在您的数据将按文件分组发送,而不是按属性分组。

【讨论】:

【参考方案12】:

我的工作是这样的:

var images = document.getElementById('fileupload').files;
var formData = new FormData();
for(i=0; i<images.length; i++) 
     formData.append('files', images[i]);

【讨论】:

【参考方案13】:

这对我有用

var ins = $('.file').map(function () 
    return this.files;
).get();

for (var x = 0; x < ins; x++) 
    formData.append("file", ins[x][0]);

【讨论】:

【参考方案14】:

如果您正在实例化 FormData 对象,该对象已经将表单作为构造函数参数传递,则输入文件的名称属性必须包含方括号。

HTML:

<form id="myForm" method="POST" action="url" enctype="multipart/form-data">
<input class="form-control form-control-lg" type="file" name="photos[]" multiple />

JS:

var formData = new FormData(document.getElementById('myForm'));
console.log(formData.getAll('photos[]'));

这对我有用!

【讨论】:

【参考方案15】:

如果我们在 html 中有输入:

<input id="my-input" type="file" mutliple /> // multiple attribute to select and upload multiple files

我们可以从该输入中获取文件并使用纯 js 脚本将其发送到服务器:

const myInput = document.getElementById('my-input') // getting our input

myInput.addEventListener('change', (event) =>  // listening for file uploads
    const files = event.target.files // getting our files after upload
    const formData = new FormData() // create formData

    for (const file of files) 
        formData.append('files', file) // appending every file to formdata
    

    const URL = 'http://server.com:3000'
    const response = fetch(URL, 
       method: 'POST',
       data: formData // sending our formdata in body of post request
    )

    return response.json() 

它非常适合我

P.S.:我在后端(node.js + express)使用multer,添加到文件上传路径

upload.array("files", 10)
第一个参数是我们文件的属性名称(在 formdata 中) 第二个参数是最大文件大小

【讨论】:

域不使用端口(@98​​7654325@),仅适用于本地服务器。 是的,当然,如果您在前端上传图片,您会获取图片并将其发送到带有 host:port 的后端服务器 是的,本地服务器不是域。

以上是关于使用 formData() 上传多个文件的主要内容,如果未能解决你的问题,请参考以下文章

[FE] 用 FormData 上传多个文件到 MultipartFile[] 接口

在 Angular 5 中使用文件上传保存 FormData

为啥 formData 不适用于多个文件?

formdata怎么上传文件和数据

FormData对象

上传多个图像不会添加到FormData