簡體   English   中英

如何使用Java App Engine正確上傳(映像)文件到Google雲端存儲?

[英]How to properly upload (image) file to Google Cloud Storage using Java App Engine?

我有一個使用Java(sdk 1.9.7)的Google App Engine實例,它已連接到Google Cloud Storage。 我能夠成功接收請求的輸入並將其輸出到我的Google雲存儲桶中的文件/對象。 這是我的servlet代碼:

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    // read the input stream
    byte[] buffer = new byte[1024];
    List<byte[]> allBytes = new LinkedList<byte[]>();
    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--

我如何告訴雲存儲我想將數據存儲為文件?

這對我有用

要上傳,請使用

curl -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();
        }
      }

}

參考文獻:楊奕森的答案和本帖

雖然另一篇文章的上傳大小限制<32 mb,但對我來說這不是問題。 此代碼還自動處理mime類型。

據我所知,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://docs.oracle.com/javaee/6/tutorial/doc/gmhba.html

選項B可能是更好的選擇,因為它可以用於表單和表單上傳。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM