fileReader.readAsBinaryString फ़ाइलों को अपलोड करने के लिए


83

AJAX के माध्यम से सर्वर पर PNG फ़ाइल अपलोड करने के लिए fileReader.readAsBinaryString का उपयोग करने की कोशिश कर रहा है, कोड को छीन लिया गया है (fileObject वस्तु है जो मेरी फ़ाइल पर जानकारी युक्त है);

var fileReader = new FileReader();

fileReader.onload = function(e) {
    var xmlHttpRequest = new XMLHttpRequest();
    //Some AJAX-y stuff - callbacks, handlers etc.
    xmlHttpRequest.open("POST", '/pushfile', true);
    var dashes = '--';
    var boundary = 'aperturephotoupload';
    var crlf = "\r\n";

    //Post with the correct MIME type (If the OS can identify one)
    if ( fileObject.type == '' ){
        filetype = 'application/octet-stream';
    } else {
        filetype = fileObject.type;
    }

    //Build a HTTP request to post the file
    var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + unescape(encodeURIComponent(fileObject.name)) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf + e.target.result + crlf + dashes + boundary + dashes;

    xmlHttpRequest.setRequestHeader("Content-Type", "multipart/form-data;boundary=" + boundary);

    //Send the binary data
    xmlHttpRequest.send(data);
}

fileReader.readAsBinaryString(fileObject);

अपलोड करने से पहले फ़ाइल की पहली कुछ पंक्तियों की जांच करना (VI का उपयोग करके) मुझे देता है

यहाँ छवि विवरण दर्ज करें

अपलोड दिखाने के बाद वही फ़ाइल

यहाँ छवि विवरण दर्ज करें

तो यह कहीं न कहीं एक प्रारूपण / एन्कोडिंग मुद्दे की तरह दिखता है, मैंने कच्चे बाइनरी डेटा पर एक साधारण UTF8 एनकोड फ़ंक्शन का उपयोग करने की कोशिश की

    function utf8encode(string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    )

फिर मूल कोड में

//Build a HTTP request to post the file
var data = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + unescape(encodeURIComponent(file.file.name)) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf + utf8encode(e.target.result) + crlf + dashes + boundary + dashes;

जो मुझे का उत्पादन देता है

यहाँ छवि विवरण दर्ज करें

अभी भी कच्ची फ़ाइल नहीं थी = (

एन्कोडिंग समस्याओं से बचने के लिए मैं फ़ाइल को कैसे एन्कोड / लोड / प्रोसेस करता हूं, इसलिए HTTP अनुरोध में प्राप्त की जा रही फ़ाइल अपलोड होने से पहले की फाइल की तरह ही है।

कुछ अन्य संभवतः उपयोगी जानकारी, अगर fileReader.readAsBinaryString () का उपयोग करने के बजाय मैं बाइनरी डेटा प्राप्त करने के लिए fileObject.getAsBinary () का उपयोग करता हूं, तो यह ठीक काम करता है। लेकिन getAsBinary फ़ायरफ़ॉक्स में ही काम करता है। मैं यह फ़ायरफ़ॉक्स और क्रोम में परीक्षण कर रहा हूँ, दोनों मैक पर, दोनों में समान परिणाम प्राप्त कर रहा है मैक पर फिर से चलने वाले एनजीआईएनएक्स अपलोड मॉड्यूल द्वारा बैकएंड अपलोड को संभाला जा रहा है । सर्वर और क्लाइंट एक ही मशीन पर हैं। यही बात किसी भी फाइल के साथ हो रही है जिसे मैं अपलोड करने की कोशिश करता हूं, मैंने सिर्फ पीएनजी को चुना क्योंकि यह सबसे स्पष्ट उदाहरण था।

जवाबों:


74

उपयोग करें fileReader.readAsDataURL( fileObject ), यह इसे बेस 64 पर एन्कोड करेगा, जिसे आप सुरक्षित रूप से अपने सर्वर पर अपलोड कर सकते हैं।


8
जबकि यह काम करता है, सर्वर पर सहेजी गई फ़ाइल का संस्करण बेस 64 एन्कोडेड है (जैसा कि यह होना चाहिए)। क्या बेस 64 एनकोडेड के बजाय बाइनरी डेटा के रूप में इसे स्थानांतरित करने का कोई तरीका नहीं है (आईई के रूप में यद्यपि यह एक सामान्य <input type="file">क्षेत्र का उपयोग करके अपलोड किया गया था )
Smudge

2
यदि आपके पास सर्वर पर PHP है तो आप इसे स्टोर करने से पहले base64_decode (फ़ाइल) कर सकते हैं। और नहीं - http पर कच्चे बाइनरी डेटा को स्थानांतरित करने का कोई सुरक्षित तरीका नहीं है।
c69

ReadAsDataURL का उपयोग करते हुए मुझे इस देता है imgur.com/1LHya सर्वर पर, पीएचपी के base64_decode के माध्यम से इसे वापस चल रहा है (हम वास्तव में अजगर का उपयोग कर रहे हैं, लेकिन पीएचपी एक अच्छा परीक्षण है) मैं imgur.com/0uwhy अभी भी नहीं मूल बाइनरी डेटा और, एक मान्य छवि नहीं = (
स्मज करें

20
@ imgur.com/1LHya हे, मेरा बुरा! सर्वर पर, आपको "," द्वारा बेस 64 स्ट्रिंग को विभाजित करना होगा और केवल दूसरे भाग को स्टोर करना होगा - इसलिए माइम प्रकार को वास्तविक फ़ाइल सामग्री के साथ संग्रहीत नहीं किया जाएगा।
c69

7
नहीं, यह कुशल नहीं है। इससे फ़ाइल का आकार 137% बढ़ जाएगा और सर्वर ओवरहेड हो जाएगा। लेकिन F *** IE का समर्थन करने का कोई और तरीका नहीं है
puchu

109

(निम्नलिखित एक देर से लेकिन पूर्ण उत्तर है)

FileReader विधियाँ समर्थन करती हैं


FileReader.readAsBinaryString()है पदावनत। इसका उपयोग न करें! यह अब W3C फ़ाइल API वर्किंग ड्राफ्ट में नहीं है :

void abort();
void readAsArrayBuffer(Blob blob);
void readAsText(Blob blob, optional DOMString encoding);
void readAsDataURL(Blob blob);

NB: ध्यान दें कि Fileएक विस्तारित Blobसंरचना है।

मोज़िला अभी भी लागू होता है readAsBinaryString()और MDN FileApi प्रलेखन में इसका वर्णन करता है :

void abort();
void readAsArrayBuffer(in Blob blob); Requires Gecko 7.0
void readAsBinaryString(in Blob blob);
void readAsDataURL(in Blob file);
void readAsText(in Blob blob, [optional] in DOMString encoding);

readAsBinaryString()पदावनति के पीछे का कारण मेरी राय में निम्नलिखित है: जावास्क्रिप्ट स्ट्रिंग्स के लिए मानक DOMStringकेवल यूटीएफ -8 वर्णों को स्वीकार करते हैं, न कि यादृच्छिक द्विआधारी डेटा। इसलिए readAsBinaryString () का उपयोग न करें, यह सुरक्षित और ECMAScript-compliant बिल्कुल नहीं है।

हम जानते हैं कि जावास्क्रिप्ट तार बाइनरी डेटा को स्टोर करने के लिए नहीं हैं, लेकिन किसी तरह से मोज़िला। मेरी राय में यह खतरनाक है। Blobऔर typed arrays( ArrayBufferऔर अभी तक लागू नहीं, लेकिन आवश्यक नहीं StringView) एक उद्देश्य के लिए आविष्कार किया गया था: UTF-8 तार प्रतिबंध के बिना, शुद्ध बाइनरी डेटा के उपयोग की अनुमति दें।

XMLHttpRequest अपलोड समर्थन


XMLHttpRequest.send() निम्नलिखित इनवोकेशन विकल्प हैं:

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);

XMLHttpRequest.sendAsBinary() निम्नलिखित इनवोकेशन विकल्प हैं:

void sendAsBinary(   in DOMString body );

sendAsBinary () क्रोम में एक मानक नहीं है और इसका समर्थन नहीं किया जा सकता है।

समाधान


तो आपके पास कई विकल्प हैं:

  1. send()FileReader.resultके FileReader.readAsArrayBuffer ( fileObject )। यह हेरफेर करने के लिए अधिक जटिल है (आपको इसके लिए एक अलग भेजना होगा () करना होगा) लेकिन यह अनुप्रयुक्त एप्लिकेशन है
  2. send()FileReader.resultके FileReader.readAsDataURL( fileObject )। यह बेकार ओवरहेड और संपीड़न विलंबता उत्पन्न करता है, सर्वर-साइड पर एक विघटन कदम की आवश्यकता होती है लेकिन यह जावास्क्रिप्ट में एक स्ट्रिंग के रूप में हेरफेर करना आसान है।
  3. अमानक और होने के नाते कीsendAsBinary()FileReader.resultFileReader.readAsBinaryString( fileObject )

MDN कहता है कि:

द्विआधारी सामग्री भेजने के लिए सबसे अच्छा तरीका है (जैसे फाइल अपलोड में) ArrayBuffers या Blobs को सेंड () विधि के साथ संयोजन के रूप में उपयोग कर रहा है। हालाँकि, यदि आप एक कठोर कच्चे डेटा भेजना चाहते हैं, तो sendAsBinary () विधि का उपयोग करें, या StringView (गैर मूल) टाइप किए गए सरणियों सुपरक्लास।


10
मैं इसे फिर से खोदने के लिए माफी चाहता हूं, बस यह जोड़ना चाहता था कि शायद बाइनरी डेटा (आदि एक पीडीएफ फाइल) भेजने का सबसे आसान तरीका केवल भेजने के बजाय हैंडलर के माध्यम से FileReader.readAsDataURLऔर (जो एक साफ बेस 64 एन्कोडेड स्ट्रिंग नहीं है) कुछ रेगेक्स के साथ इसे पहले साफ करें और वास्तविक आधार 64 को सर्वर पर डीकोड किया जाए। onloadevent.target.resultevent.target.result = event.target.result.match(/,(.*)$/)[1]

चूँकि कोई भी एमडीएन को संपादित कर सकता है, मैं शायद इसे स्रोत के रूप में उपयोग नहीं करूंगा।
क्रिस एंडरसन

4
@ user1299518, बेहतर उपयोग event.target.result.split(",", 2)[1], नहीं match
Mrssn

1
@ क्रिसविडेव: अनुशंसित विकल्प में आप एक अलग भेजने की आवश्यकता का उल्लेख करते हैं ()। क्यों?
8

अनुशंसित दृष्टिकोण ने TFS REST API का उपयोग करके अनुलग्नक अपलोड करने के लिए काम किया। धन्यवाद!
रोजा

24

यदि इसका समर्थन करने वाले ब्राउज़रों में सबसे अच्छा तरीका है, फ़ाइल को ब्लॉब के रूप में भेजना, या यदि आप एक मल्टीपार्ट फॉर्म चाहते हैं तो फॉर्मडाटा का उपयोग करना है। उसके लिए आपको FileReader की आवश्यकता नहीं है। यह डेटा को पढ़ने की कोशिश करने की तुलना में सरल और अधिक कुशल दोनों है।

यदि आप विशेष रूप से इसे भेजना चाहते हैं multipart/form-data, तो आप फॉर्मडाटा ऑब्जेक्ट का उपयोग कर सकते हैं:

var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", '/pushfile', true);
var formData = new FormData();
// This should automatically set the file name and type.
formData.append("file", file);
// Sending FormData automatically sets the Content-Type header to multipart/form-data
xmlHttpRequest.send(formData);

आप उपयोग करने के बजाय सीधे डेटा भी भेज सकते हैं multipart/form-dataप्रलेखन देखें । बेशक, इसके लिए सर्वर-साइड बदलाव की भी आवश्यकता होगी।

// file is an instance of File, e.g. from a file input.
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", '/pushfile', true);

xmlHttpRequest.setRequestHeader("Content-Type", file.type);

// Send the binary data.
// Since a File is a Blob, we can send it directly.
xmlHttpRequest.send(file);

ब्राउज़र समर्थन के लिए, देखें: http://caniuse.com/#feat=xhr2 (IE 10+ सहित अधिकांश ब्राउज़र)।


xmlHttpRequest.send (formData);
ली-चुह वू नोव

7
अंत में एक उचित उत्तर भी उपयोग किए बिना FormData। ऐसा लगता है कि हर कोई एक फॉर्म का उपयोग कर रहा है, जबकि उन्हें केवल एक फ़ाइल अपलोड करने की आवश्यकता है ... धन्यवाद!
विल्ट

मैं घंटे के लिए देख रहा था कि यह कैसे ajax के माध्यम से एक एमपी 3 फ़ाइल अपलोड के लिए काम कर रहा है, यह चाल है!
जस्टिन विंसेंट

एक बात जो मुझे लगता है कि आपको सेट-टेस्टरहेयर करने की आवश्यकता नहीं है क्योंकि यह फ़ॉर्मडैटा भेजकर ऑटो सेट हो जाएगा और कुछ इस तरह दिखाई देगा "सामग्री-प्रकार: मल्टीपार्ट / फॉर्म-डेटा; सीमा = ---- वेबकिर्फ़ॉर्मबोररी क्यूए 8 डी 7 एलएपी 6 केएसकेए" जब तक मैंने setRequestHeader को हटा नहीं दिया।
जस्टिन विंसेंट

नोट: ऊपर दी गई मेरी टिप्पणी केवल फॉर्मडाटा ऑब्जेक्ट का उपयोग करते समय लागू होती है।
जस्टिन विंसेंट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.