如何使用Java App Engine正确上传(映像)文件到Google云端存储?

我有一个谷歌应用引擎实例,使用java(sdk 1.9.7),它连接到谷歌云存储。 我能够成功接收请求的输入并将其输出到我的Google云存储桶中的文件/对象。 这是我的servlet代码:

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { // read the input stream byte[] buffer = new byte[1024]; List allBytes = new LinkedList(); InputStream reader = req.getInputStream(); while(true) { int bytesRead = reader.read(buffer); if (bytesRead == -1) { break; // have a break up with the loop. } else if (bytesRead < 1024) { byte[] temp = Arrays.copyOf(buffer, bytesRead); allBytes.add(temp); } else { allBytes.add(buffer); } } // init the bucket access GcsService gcsService = GcsServiceFactory.createGcsService(RetryParams.getDefaultInstance()); GcsFilename filename = new GcsFilename("my-bucket", "my-file"); Builder fileOptionsBuilder = new GcsFileOptions.Builder(); fileOptionsBuilder.mimeType("text/html"); // or "image/jpeg" for image files GcsFileOptions fileOptions = fileOptionsBuilder.build(); GcsOutputChannel outputChannel = gcsService.createOrReplace(filename, fileOptions); // write file out BufferedOutputStream outStream = new BufferedOutputStream(Channels.newOutputStream(outputChannel)); for (byte[] b : allBytes) { outStream.write(b); } outStream.close(); outputChannel.close(); } 

当我做一个像curl POST命令这样的东西时,如果我只是直接输入数据,这样就可以完美地工作,如下所示:

 curl --data "someContentToBeRead" http://myAppEngineProj.appspot.com/myServlet 

我可以看到我输入的确切字符串,“someContentToBeRead”。

但是,当我放一个文件时,如下:

 curl -F file=@"picture.jpg" http://myAppEngineProj.appspot.com/myServlet 

该文件已完全损坏。 如果我上传一个文本文件,它在文件的开头有一行废话,最后有一行废话,如:

 ------------------------------266cb0e18eba Content-Disposition: form-data; name="file"; filename="blah.txt" Content-Type: text/plain hi how are you ------------------------------266cb0e18eba-- 

我如何告诉云存储我想将数据存储为文件?

据我所知,Google云端存储或API没有问题; 在从HttpServletRequest读取内容时,问题更早。

包含—— 266cb0e18eba的行实际上是MIME编码的一部分,标记了部分的开头和结尾。

您可以通过以下两种方式之一解决问题。

选项A:保持代码相同,但更改上传数据的方式

更换:

 $ curl -F file=@"picture.jpg" http://myAppEngineProj.appspot.com/myServlet 

附:

 $ curl -X POST -d @"picture.jpg" http://myAppEngineProj.appspot.com/myServlet 

选项B:修复Java代码并在使用时继续使用curl

更换:

 java.io.InputStream is = request.getInputStream(); 

附:

 javax.servlet.http.Part filePart = request.getPart("file"); java.io.InputStream is = filePart.getInputStream() 

这将在curl构造的多部分MIME消息中的正确部分上打开输入流。

这在此记录:

http://sofzh.miximages.com/java/ppre codecurl -F file=@picture.jpg” http://myAppEngineProj.appspot.com/myServlet

而servlet看起来像

 import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.channels.Channels; import java.util.Enumeration; import java.util.logging.Logger; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.servlet.ServletFileUpload; import com.google.appengine.tools.cloudstorage.GcsFileOptions; import com.google.appengine.tools.cloudstorage.GcsFilename; import com.google.appengine.tools.cloudstorage.GcsOutputChannel; import com.google.appengine.tools.cloudstorage.GcsService; import com.google.appengine.tools.cloudstorage.GcsServiceFactory; import com.google.appengine.tools.cloudstorage.RetryParams; public class UploadServlet extends HttpServlet { private static final Logger log = Logger.getLogger(UploadServlet.class.getName()); private final GcsService gcsService = GcsServiceFactory.createGcsService(new RetryParams.Builder() .initialRetryDelayMillis(10) .retryMaxAttempts(10) .totalRetryPeriodMillis(15000) .build()); private String bucketName = "myBucketNameOnGoogleCloudStorage"; /**Used below to determine the size of chucks to read in. Should be > 1kb and < 10MB */ private static final int BUFFER_SIZE = 2 * 1024 * 1024; @SuppressWarnings("unchecked") @Override public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String sctype = null, sfieldname, sname = null; ServletFileUpload upload; FileItemIterator iterator; FileItemStream item; InputStream stream = null; try { upload = new ServletFileUpload(); res.setContentType("text/plain"); iterator = upload.getItemIterator(req); while (iterator.hasNext()) { item = iterator.next(); stream = item.openStream(); if (item.isFormField()) { log.warning("Got a form field: " + item.getFieldName()); } else { log.warning("Got an uploaded file: " + item.getFieldName() + ", name = " + item.getName()); sfieldname = item.getFieldName(); sname = item.getName(); sctype = item.getContentType(); GcsFilename gcsfileName = new GcsFilename(bucketName, sname); GcsFileOptions options = new GcsFileOptions.Builder() .acl("public-read").mimeType(sctype).build(); GcsOutputChannel outputChannel = gcsService.createOrReplace(gcsfileName, options); copy(stream, Channels.newOutputStream(outputChannel)); res.sendRedirect("/"); } } } catch (Exception ex) { throw new ServletException(ex); } } private void copy(InputStream input, OutputStream output) throws IOException { try { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead = input.read(buffer); while (bytesRead != -1) { output.write(buffer, 0, bytesRead); bytesRead = input.read(buffer); } } finally { input.close(); output.close(); } } } 

参考文献:Wilson Yeung上面的回答和本帖

虽然另一篇文章的上传大小限制<32 mb,但对我来说这不是问题。 此代码还自动处理mime类型。