AngularJS - 从base64下载文件

3

我正在尝试将文件编码为base64,然后允许用户下载同一文件的解码版本(只是我的一个训练练习;-))。

但是当我打开文件时,内容显示为“undefined”而不是最初编码的文件内容。

我在这里做错了什么,如何解决?

HTML

<form ng-submit="upload(file)">
    <input type="file" ng-model="file">
    <button type="submit" class="button success pull-right"><i class="glyphicon glyphicon-ok"></i> Add</button>
</form>
<ul>
    <li ng-repeat="link in downloads track by $index">
        <a href="{{ link.link }}" download="{{ link.link }}">{{ link.name }}<a>
    </li>
</ul>


控制器

angular.module('myApp')
.controller('testController', function ($scope) {
    $scope.upload = function(file){
        var contentType = 'text/plain';
        var b64Data = encode64(file);

        var blob = b64toBlob(b64Data, contentType);
        addLink(URL.createObjectURL(blob));
    }

    $scope.downloads = [];
    function addLink(linkAddress){
        $scope.downloads.push({
            link: linkAddress,
            name: 'test ' + ($scope.downloads.length+1)
        });
    }

    function b64toBlob(b64Data, contentType, sliceSize) {
      contentType = contentType || '';
      sliceSize = sliceSize || 512;

      var byteCharacters = decode64(b64Data);
      var byteArrays = [];

      for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        var slice = byteCharacters.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
      }

      var blob = new Blob(byteArrays, {type: contentType});
      return blob;
    }

    function encode64(input) {
        input = escape(input);
        var output = "";
        var chr1, chr2, chr3 = "";
        var enc1, enc2, enc3, enc4 = "";
        var i = 0;
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        do {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
               enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
               enc4 = 64;
            }

            output = output +
               keyStr.charAt(enc1) +
               keyStr.charAt(enc2) +
               keyStr.charAt(enc3) +
               keyStr.charAt(enc4);
            chr1 = chr2 = chr3 = "";
            enc1 = enc2 = enc3 = enc4 = "";
        } while (i < input.length);

        return output;
    }

    function decode64(input) {
        var output = "";
        var chr1, chr2, chr3 = "";
        var enc1, enc2, enc3, enc4 = "";
        var i = 0;
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
        var base64test = /[^A-Za-z0-9\+\/\=]/g;
        if (base64test.exec(input)) {
            console.error("There were invalid base64 characters in the input text.\n" +
                "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
                "Expect errors in decoding.");
        }
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        do {
            enc1 = keyStr.indexOf(input.charAt(i++));
            enc2 = keyStr.indexOf(input.charAt(i++));
            enc3 = keyStr.indexOf(input.charAt(i++));
            enc4 = keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
               output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
               output = output + String.fromCharCode(chr3);
            }

            chr1 = chr2 = chr3 = "";
            enc1 = enc2 = enc3 = enc4 = "";

        } while (i < input.length);

        return unescape(output);
    }
});

你有检查过 file 的值吗?提示:Angular 没有对 input[file] 提供内置支持。 - a better oliver
1个回答

2
您需要使用 FileReader 来读取文件内容。 我还使用了一个 promise(使用 AngularJS 的 $q )来在FileReader完成加载文件内容并对其进行编码后解析。
通过 document.getElementById() 获取 fileInput 元素不符合 Angular 的方式,但是您可以借此想到自己的练习。
我已经改进了您的代码:
function encode64() {
    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];
    var deferred = $q.defer();

    var reader = new FileReader();
    reader.onload = function(e) {
        var input = reader.result;

        var output = "";
        var chr1, chr2, chr3 = "";
        var enc1, enc2, enc3, enc4 = "";
        var i = 0;
        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

        do {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
                keyStr.charAt(enc1) +
                keyStr.charAt(enc2) +
                keyStr.charAt(enc3) +
                keyStr.charAt(enc4);
            chr1 = chr2 = chr3 = "";
            enc1 = enc2 = enc3 = enc4 = "";
        } while (i < input.length);
        deferred.resolve(output);
    }
    reader.readAsText(file);
    return deferred.promise;
}

$scope.upload = function() {
    var contentType = 'text/plain';
    encode64().then(function(b64Data){
        var blob = b64toBlob(b64Data, contentType);
        addLink(URL.createObjectURL(blob));
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接