您的位置:首页 > 理论基础 > 计算机网络

Uploading and Downloading Files

2012-04-14 08:10 253 查看

Uploading and Downloading Files

Edit

Watch

Table of contents

1.
HTTP File Upload
2.
HTTP PUT
3.
Downloading Files

Tags

Files

Page Notifications
Off

Table of contents
1.
HTTP File Upload
2.
HTTP PUT
3.
Downloading Files

File and Stream Guide: [

nsIScriptableIO |
Accessing Files |
Getting File Information |
Reading from Files |
Writing to Files |
Moving, Copying and Deleting Files | Uploading and Downloading Files |

Working With Directories ]

Important note: The pages from the File and Stream Guide use the
IO
 object (
nsIScriptableIO
), which was not available in any released version of the platform (pending

some fixes). There are alternative XPCOM APIs you can use, your help in updating this pages to use the supported API is very much welcome!
Other documentation on files and I/O not using the unavailable nsIScriptableIO APIs:

Code snippets: File I/O,
Open and Save Dialogs,
Reading textual data,
Writing textual data,
List of file-related error codes.

The IO object and stream objects can be used to upload files to servers in various ways. The exact method depends on the type of upload that you wish to perform.

HTTP File Upload

Some web sites allow one to upload a file. This is done by using an HTML <input> element using the
file
type from within a form. When the user selects a file, it can be uploaded to a server. This operation can also be performed via a script using the XMLHttpRequest object. This is a common technique for uploading files as it is compatible with
existing servers. However, this is a fairly complicated method.

File upload via a form involves the use of data in a multipart stream. One part will contain the file data and the other part will contain any other form parameters. However, each part is optional. Each part is separated with a boundary string which can
be any string, but should not occur within the file or elsewhere in the data being sent. This allows the host to distinguish where each part ends and the next one begins.

For example, the raw data for a typical upload might look like the following:

Content-type: multipart/form-data; boundary=abcd
Content-length: 20
--abcd
Content-Disposition: form-data; name="fieldname"; filename="sample.txt"
Content-type: text/plain

This is sample text

--abcd

As can be seen, the boundary is specified in the first line as 'abcd'. When used on subsequent lines, it is always preceded by two hyphens. The first part after the initial header indicates a file that is being uploaded. The desired filename is specified
as 'sample.txt'. The name specified as 'fieldname' corresponds to the name specified on an HTML input form control if this had been uploaded from an HTML form.

The content of the file to upload is specified as the body of the part, in this case with the type
text/plain
. Other content types could be used to upload content of other types.

You could perform the upload by just writing content like that above. However, it may be convenient in some cases to use the stream interfaces instead. The following is a sample function which uploads a file given by the first argument, to a url given by
the second argument. The name argument is the field name.

function upload(file, posturl, name)
{
var boundary = "--------XX" + Math.random();

var req = new XMLHttpRequest();
req.open("POST", posturl);
req.setRequestHeader("Content-type", "multipart/form-data; boundary=" + boundary);
req.setRequestHeader("Content-length", file.fileSize);
req.onload = function(event) { alert(event.target.responseText); }

var prefix = "--" + boundary + "\n" +
"Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" +
file.leafName + "\"\n" +
"Content-type: text/plain\n\n";
var stream = IO.newInputStream(prefix, "multi");
stream.appendStream(IO.newInputStream(file, ""));
stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

req.send(stream);
}

When the content is uploaded, the 'onload' handler will display the response. You would want to alter this portion to perform whatever operations are necessary with the response data.

The boundary string is generated from a random number. You can see here that this string is used twice to mark the beginning and end of the file data. Note that in this example, no check is performed to ensure that the boundary string doesn't exist within
the file. Although unlikely, an error could occur if the boundary happened to appear within the file data, so you may wish to read the file first.

The interesting aspect of this example is that it uses a multi stream, to indicate multiple parts of a stream. Here is this portion of the function above.

var stream = IO.newInputStream(prefix, "multi");
stream.appendStream(IO.newInputStream(file, ""));
stream.appendStream(IO.newInputStream("\n--" + boundary + "\n", ""));

req.send(stream);

Three streams are created, one for the data that comes before the file data, one for the file itself, and the third for the final boundary string. A multi stream is created using the
multi
flag. A multi stream indicates a stream where additional pieces may be appended to it. Each piece will be merged together in sequence, as if all of the pieces were one larger stream. The first stream is read from the 'prefix' string. Each
additional stream is added to the multi stream using
nsIMultiplexInputStream.appendStream()

. The second stream is created from a file, which was supplied as an argument to the
upload
function. Finally, the third stream is created from a string. The result is sent to the remote host and the streams will be read from in sequence as needed.

A multi stream works even though two of the parts are read from a string and one part is read from a file. To the XMLHttpRequest object, it is as if all of the data was in one stream all along.

Example HTTP POST for multipart/form-data (Using XPCOM syntax)

//Buffer the upload file
var inStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
inStream.init(nsIFile, 1, 1, inStream.CLOSE_ON_EOF);
var bufInStream = Cc["@mozilla.org/network/buffered-input-stream;1"].createInstance(Ci.nsIBufferedInputStream);
bufInStream.init(inStream, 4096);

//Setup the start Boundery stream
var boundary = "X-------------X" + Math.random();
var startBoundaryStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
startBoundaryStream.setData("\r\n--"+boundary+"\r\n", -1);

//Setup the middle Boundary stream
var boundaryStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
boundaryStream.setData("\r\n--"+boundary+"\r\n", -1);

//Setup the end Boundery stream
var endBoundaryStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
endBoundaryStream.setData("\r\n--"+boundary+"--", -1);

//Setup the binary data (file upload) mime-stream
var file_mimeStream = Cc["@mozilla.org/network/mime-input-stream;1"].createInstance(Ci.nsIMIMEInputStream);
file_mimeStream.addContentLength = false;
file_mimeStream.addHeader("Content-disposition","form-data; name=\"aValue\"; filename=\""+nsIFile.leafName+"\"");
file_mimeStream.addHeader("Content-type","application/octet-stream;");
file_mimeStream.setData(bufInStream);

//Setup the "user" mime-stream
var user_mimeStream = Cc["@mozilla.org/network/mime-input-stream;1"].createInstance(Ci.nsIMIMEInputStream);
user_mimeStream.addContentLength = false;
user_mimeStream.addHeader("Content-disposition", "form-data; name=\"user\"");
var strStream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
strStream.setData("SteveJobs", -1);
user_mimeStream.setData(strStream);

//Setup the multiplex stream to combine the necessary streams
var multiStream = Cc["@mozilla.org/io/multiplex-input-stream;1"].createInstance(Ci.nsIMultiplexInputStream);
multiStream.appendStream(startBoundaryStream);
multiStream.appendStream(file_mimeStream);
multiStream.appendStream(boundaryStream);
multiStream.appendStream(user_mimeStream);
multiStream.appendStream(endBoundaryStream);

//Setup the POST request
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
req.open("POST", URL_VALUE, false);  //false makes this an asyncronous request
req.setRequestHeader("Content-type", "multipart/form-data; boundary="+boundary);
req.setRequestHeader("Content-length", multiStream.available());

//Send the request (finally!)
req.send(multiStream);


HTTP PUT

You can also upload a file using an HTTP PUT operation. This doesn't require the multipart content as above and is much simpler, however web servers usually need special configuration to support PUT operations.

function uploadPut(file, posturl)
{
var req = new XMLHttpRequest();
req.open("PUT", posturl);
req.setRequestHeader("Content-type", "text/plain");
req.setRequestHeader("Content-length", file.fileSize);
req.onload = function(event) { alert(event.target.responseText); }

var stream = IO.newInputStream(file, "");
req.send(stream);
}

In this example, a new input stream is created for a file, and is passed to the XMLHttpRequest's
send
method.

Downloading Files

To come...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息