Получить кодирование файловых данных 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

Но это возвращает только ошибку en в методе UTF_8 до того, как он закодирует base64? (или пустая строка)

var encoded = Base64.encode(file); 
jordan.baucke
источник
Что вы загружаете? Текстовые данные или двоичные?
beatgammit 08
@tjamenson бинарные данные - что-нибудь действительно 'текстовый документ' 'pdf' 'изображение' и т. д. Я собирался присвоить имя файла другой переменной, но я начал задаваться вопросом, есть ли у меня какой-то фатальный недостаток в моем понимании того, что возможно с загружать формы и html - этот метод совершенно невыполним, и невозможно ли передать данные файла, разместив их в виде строки? Также без HTML5, который я читаю, есть некоторые решения -
jordan.baucke
Интересный. Почему вы используете кодировку base-64 между браузером и сервером и пытаетесь сделать это в браузере? Похоже, что если вы пытаетесь защитить данные, SSL будет намного проще, поскольку он шифрует все данные HTTP (включая файлы) по сети. И вы можете использовать серверную часть base-64, если это необходимо для вашей базы данных.
Уильям Уолсет,
@William Я не пытаюсь защитить данные, просто приведите их в правильный формат. Salesforce.com (платформа Apex) требует, чтобы база данных была закодирована в base64 до того, как запись будет создана в базе данных, их функциональность по кодированию файловых данных base64 через форму очень плохо документирована (я понял, как это сделать, задав этот вопрос). В любом случае, похоже, что данные двоичного файла с кодировкой base64 изначально поддерживаются только в HTML5 или Mozilla File API
jordan.baucke
1
Хорошо, теперь я понимаю, зачем тебе это нужно. Нет промежуточного сервера + сумасшедшие требования к облаку + отсутствие кроссбраузерного решения = 1 беспорядок. Сожалею.
Уильям Уолсет

Ответы:

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:

beatgammit
источник
отлично - я думал, readAsArrayBuffer()что вывести то, что выглядело как правильные данные base64 , но это не могло быть обработано из-за начальной части строки - сейчас я попробую!
jordan.baucke 08
1
readAsArrayBuffer (), похоже, не существует в Chrome / Safari, и я предполагаю, что это будет проблематично в других браузерах ~ есть ли эквивалент, который я могу использовать в этих других браузерах?
jordan.baucke
createObjectURL () <- это выглядит многообещающе. Я постараюсь реализовать это, но я уверен, что IE понадобится 3-е колесо
jordan.baucke
Можно ли присвоить имя файла перед выполнением решения для загрузки?
Ωmega
@ Ωmega - Нет. Все это загружает двоичный поток. Нет способа (AFAIK) указать имя файла. Однако некоторые браузеры угадывают расширение. Чтобы получить имена файлов, вам нужно будет загрузить, а затем снова загрузить.
beatgammit
38

Мое решение было использовать 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
Самый простой способ, почему у него нет большего количества голосов?
sarink 01
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

После того, как я сам с этим боролся, я пришел к реализации FileReader для браузеров, которые его поддерживают (Chrome, Firefox и еще не выпущенный Safari 6), а также PHP-скрипт, который возвращает данные файла POSTed в виде данных в кодировке Base64 для других браузеры.

Крис Нолет
источник
0

Я начал думать, что использование iframe для загрузки в стиле Ajax может быть гораздо лучшим выбором для моей ситуации, пока HTML5 не вернется на круги своя, и мне не придется поддерживать устаревшие браузеры в моем приложении!

jordan.baucke
источник
Просто любопытно, почему бы вам просто не взять [ 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
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)
mb21
источник