从输入表单获取Base64编码的文件数据


100

我有一个基本的HTML表单,可以从中获取一些正在Firebug中检查的信息。

我唯一的问题是,在将文件数据发送到服务器之前,我试图对文件数据进行base64编码,然后将其以该格式保存到数据库。

<input type="file" id="fileupload" />

在Javascript + jQuery中:

var file = $('#fileupload').attr("files")[0];

我有一些基于可用javascript的操作:.getAsBinary()、. getAsText()、. getAsTextURL

但是,这些都不返回可插入的可用文本,因为它们包含不可用的“字符” -我不想在上传的文件中出现“回发”,并且我需要针对特定​​对象的多种形式,因此我很重要获取文件并以这种方式使用Javascript。

我应该如何以一种可以使用广泛使用的Javascript base64编码器的方式获取文件?

谢谢

更新-从这里开始赏金,需要跨浏览器支持!!!

这是我的位置:

<input type="file" id="fileuploadform" />

<script type="text/javascript">
var uploadformid = 'fileuploadform';
var uploadform = document.getElementById(uploadformid);


/* method to fetch and encode specific file here based on different browsers */

</script>

跨浏览器支持的几个问题:

var file = $j(fileUpload.toString()).attr('files')[0];
fileBody = file.getAsDataURL(); // only would works in Firefox

此外,IE不支持:

var file = $j(fileUpload.toString()).attr('files')[0];

所以我必须替换为:

var element = 'id';
var element = document.getElementById(id);

对于IE支持。

此功能可在Firefox,Chrome和Safari中使用(但无法正确编码文件,或者至少在文件发布后无法正确显示)

var file = $j(fileUpload.toString()).attr('files')[0];
var encoded = Btoa(file);

也,

file.readAsArrayBuffer() 

似乎仅在HTML5中受支持?

很多人建议: http : //www.webtoolkit.info/javascript-base64.html

但这只会在base64编码之前在UTF_8方法上返回en错误?(或空字符串)

var encoded = Base64.encode(file); 

您要上传什么?文本数据还是二进制?
Beatgammit 2011年

@tjamenson二进制数据-任何真正的'word document''pdf''image'等上传表单和html-此方法完全无效,并且无法通过将其发布为字符串来传输文件数据吗?同样,如果没有HTML5,我正在阅读也有一些解决方案
jordan.baucke 2011年

有趣。为什么要在浏览器和服务器之间进行base-64编码,并尝试在浏览器中完成此操作?好像您要保护数据一样,SSL会更容易,因为它可以通过网络对所有HTTP数据(包括文件)进行加密。如果数据库有必要,您可以使用base-64服务器端。
威廉·沃尔瑟斯

@William我不是要保护数据,只是将其保存为正确的格式。Salesforce.com(Apex平台)要求在数据库中创建记录之前对数据库进行base64编码,但其通过表单base64编码文件数据进行编码的功能却很少记录(我问了这个问题后就想出了怎么做)。无论如何,看起来只支持HTML5Mozilla File API
jordan.baucke 2011年

1
好,现在我明白了您为什么需要这个了。没有中间服务器+疯狂的云需求+没有跨浏览器解决方案= 1个混乱。抱歉。
威廉·沃尔瑟斯

Answers:


121

在浏览器端的javascript中完全有可能。

简单的方法:

readAsDataURL()方法可能已经对其进行编码为base64为您服务。您可能需要删除开头的内容(直到第一个,),但这没什么大不了的。这将带走所有的乐趣。

困难的方法:

如果您想尝试一下困难的方法(或者不起作用),请参阅readAsArrayBuffer()。这将为您提供一个Uint8Array,您可以使用指定的方法。这可能仅在您想要弄乱数据本身(例如,在上载之前操纵图像数据或进行其他伏都教具魔术)时有用。

有两种方法:

  • 转换为字符串并使用内置的btoa或类似的
    • 我还没有测试所有情况,但是对我有用-只需获取字符代码
  • 直接从Uint8Array转换为base64

我最近在浏览器中实现了tar。作为该过程的一部分,我进行了自己的直接Uint8Array-> base64实现。我认为您不需要它,但是如果您想看看,就在这里。它非常整洁。

我现在应该做什么:

从Uint8Array转换为字符串的代码非常简单(其中buf是Uint8Array):

function uint8ToString(buf) {
    var i, length, out = '';
    for (i = 0, length = buf.length; i < length; i += 1) {
        out += String.fromCharCode(buf[i]);
    }
    return out;
}

从那里开始:

var base64 = btoa(uint8ToString(yourUint8Array));

Base64现在将是一个以base64编码的字符串,它应该仅上载桃子。如果要在推送之前仔细检查,请尝试以下操作:

window.open("data:application/octet-stream;base64," + base64);

这会将其下载为文件。

其他资讯:

要将数据作为Uint8Array获得,请查看MDN文档:


太好了-我以为readAsArrayBuffer()输出看起来像正确的base64数据,但是由于字符串的乞讨部分而无法处理-我现在就来试试吧!
jordan.baucke 2011年

1
在Chrome / Safari中似乎不存在readAsArrayBuffer(),并且我认为在其他浏览器中会出现问题〜我可以在这些其他浏览器中使用等效的功能吗?
jordan.baucke 2011年

createObjectURL()<-这看起来很有希望,我将尝试实现它,但是我确定IE将需要第三个轮子
jordan.baucke 2011年

执行下载解决方案之前可以分配文件名吗?
Ωmega

@Ωmega-否。所有这些操作就是下载二进制流。无法(AFAIK)指定文件名。一些浏览器虽然猜测扩展。要获取文件名,您必须先上传然后重新下载。
beatgammit

37

我的解决办法是使用readAsBinaryString()btoa()它的结果。

uploadFileToServer(event) {
    var file = event.srcElement.files[0];
    console.log(file);
    var reader = new FileReader();
    reader.readAsBinaryString(file);

    reader.onload = function() {
        console.log(btoa(reader.result));
    };
    reader.onerror = function() {
        console.log('there are some problems');
    };
}

3
到目前为止,最简单的方法是为什么没有更多的选票?
凌晨

14

单击文件上传按钮时,我使用FileReader来显示图像,而不使用任何Ajax请求。以下是该代码希望对您有所帮助的代码。

$(document).ready(function($) {
    $.extend( true, jQuery.fn, {        
        imagePreview: function( options ){          
            var defaults = {};
            if( options ){
                $.extend( true, defaults, options );
            }
            $.each( this, function(){
                var $this = $( this );              
                $this.bind( 'change', function( evt ){

                    var files = evt.target.files; // FileList object
                    // Loop through the FileList and render image files as thumbnails.
                    for (var i = 0, f; f = files[i]; i++) {
                        // Only process image files.
                        if (!f.type.match('image.*')) {
                        continue;
                        }
                        var reader = new FileReader();
                        // Closure to capture the file information.
                        reader.onload = (function(theFile) {
                            return function(e) {
                                // Render thumbnail.
                                    $('#imageURL').attr('src',e.target.result);                         
                            };
                        })(f);
                        // Read in the image file as a data URL.
                        reader.readAsDataURL(f);
                    }

                });
            });
        }   
    });
    $( '#fileinput' ).imagePreview();
});

1

在自己解决这个问题之后,我开始为支持它的浏览器(Chrome,Firefox和尚未发布的Safari 6)实现FileReader,以及一个PHP脚本,该脚本将POST文件的数据作为Base64编码的数据回传给其他人浏览器。


0

我开始认为在HTML5全面发展之前,使用'iframe'进行Ajax样式上传可能是一种更好的选择,而我不必在我的应用程序中支持旧版浏览器!


很好奇,为什么不直接使用[ webtoolkit.info/javascript-base64.html#]然后注释掉input = Base64._utf8_encode(input);并添加output = Base64._utf8_decode(output);?除utf-8转换错误外是否还有其他问题?
shr

@shr我不知道如何获取二进制文件数据以在每个浏览器中输入这些方法?$('#inputid').files[0]据我所知,在IE7中不起作用)。如果那么容易吗?var output = Base64.encode($('#inputid').files[0])??
jordan.baucke 2011年

0

受@Josef的答案启发:

const fileToBase64 = async (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => resolve(reader.result)
    reader.onerror = (e) => reject(e)
  })

const file = event.srcElement.files[0];
const imageStr = await fileToBase64(file)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.