我正在尝试编写一个Android应用程序,它将拍摄照片,将数据(byte [])与一些元数据放在一个对象中,并将其发布到AppEngine服务器,在那里它将作为一个数据存储区保存在数据存储区中斑点。我真的不想将图像保存为Android上的文件(除非绝对必要)。我四处寻找解决方案,但没有任何明确或具体的内容。我的问题是:
代码示例非常有用。此外,如果我采取的方法太复杂或有问题,请建议其他方法(例如将图像保存为文件,发布到服务器,然后删除)。
答案 0 :(得分:8)
你只需要在POST的特殊情况下做一个Http-FileUpload。 无需对文件进行uuencode。 无需使用特殊的lib / jar 无需将对象保存到磁盘(无论以下示例是这样做的)
您可以找到关于Http-Command的非常好的解释,以及
下您特别关注的“文件上传”Using java.net.URLConnection to fire and handle HTTP requests
以下是文件上传示例(观看“发送二进制文件”) 并且可以添加一些伴随数据
String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
OutputStream output = connection.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true = autoFlush, important!
// Send normal param.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF);
writer.append(param).append(CRLF).flush();
// Send text file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF).flush();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
for (String line; (line = reader.readLine()) != null;) {
writer.append(line).append(CRLF);
}
} finally {
if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
}
writer.flush();
// Send binary file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName()).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF).flush();
InputStream input = null;
try {
input = new FileInputStream(binaryFile);
byte[] buffer = new byte[1024];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.flush(); // Important! Output cannot be closed. Close of writer will close output as well.
} finally {
if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}
writer.append(CRLF).flush(); // CRLF is important! It indicates end of binary boundary.
// End of multipart/form-data.
writer.append("--" + boundary + "--").append(CRLF);
} finally {
if (writer != null) writer.close();
}
关于问题的第二部分。成功上传文件(我使用apache常用文件)后,将blob作为图像传输并不是什么大问题。
这是如何接受servlet中的文件
public void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse)
throws ServletException, IOException {
ServletFileUpload upload = new ServletFileUpload();
try {
FileItemIterator iter = upload.getItemIterator (pRequest);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String fieldName = item.getFieldName();
InputStream stream = item.openStream();
....
stream.close();
}
...
此代码提供图像
public void doGet (HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException {
try {
Blob img = (Blob) entity.getProperty(propImg);
pResponse.addHeader ("Content-Disposition", "attachment; filename=abc.png");
pResponse.addHeader ("Cache-Control", "max-age=120");
String enc = "image/png";
pResponse.setContentType (enc);
pResponse.setContentLength (img.getBytes().length);
OutputStream out = pResponse.getOutputStream ();
out.write (img.getBytes());
out.close();
我希望此代码片段有助于回答您的问题
答案 1 :(得分:6)
1.您可以使用以下命令将byte []编码为base64:
http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html
2.使用HTTP POST请求向AppEngine servlet发送该数据。
3.配置AppEngine以接受servlet。
4.然后您可以选择将其保存到数据存储区或Blobstore。 - 我喜欢blobstore来做这些事情。
5.对base64字符串服务器端进行解码。
6.从那里开始你需要将你的字符串剪成更小的片段并将每个片段写入blobstore。
以下是将其写入blobstore的一些代码。
byte[] finalImageArray = null;
try {
finalImageArray = Base64.decode(finalImageData.getBytes()); //finalImageData is the string retrieved from the HTTP POST
} catch (Base64DecoderException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try{
FileService fileService = FileServiceFactory.getFileService();
AppEngineFile file = fileService.createNewBlobFile("image/png");
FileWriteChannel writeChannel = fileService.openWriteChannel(file, true);
int steps = (int) Math.floor(finalImageArray.length/1000);
int current = 0;
for(int i = 0; i < 1000; i++){
writeChannel.write(ByteBuffer.wrap(Arrays.copyOfRange(finalImageArray, current, steps+current)));
current = current + steps;
}
writeChannel.write(ByteBuffer.wrap(Arrays.copyOfRange(finalImageArray, current, finalImageArray.length))); //The reason it's cut up like this is because you can't write the complete string in one go.
writeChannel.closeFinally();
blobKey = fileService.getBlobKey(file);
if(blobKey == null)
blobKey = retryBloBKey(file); //My own method, AppEngine tends to not return the blobKey once a while.
}
catch(Exception e){
logger.log(Level.SEVERE,e.getMessage());
}
return blobKey.getKeyString();
编写一个servlet,使用提供的密钥检索图像数据。
享受您美丽的代码:)
//我将它保存在二进制文件中的原因是因为它为我提供了使用图像api的选项,你也可以选择以base64格式保存它。
答案 2 :(得分:2)
由于代码由三个人提供,因此您可以选择其中任何一个(或者您将在google上获得大量示例)。 有三种可能性 1)首先你的SD卡中有图像
2)您正在从服务器下载图像然后发送
3)图像作为blob存储在DataBase中
考虑每个案例的最佳方法 -
1)如果您的图像存储在SD卡中,那么只需将图像转换为位图 - &gt; byteArray - &gt;字符串并发送到服务器
2)如果您从服务器下载图像然后发送到另一个URL。然后在DataBase Table中下载所有图像URL存储。稍后当您需要发送到服务器时 获取网址,下载图像并存储在缓存中。然后类似地发送服务器并刷新缓存
3)建议不要在DB中存储大量图像。但是如果你有必要这样做,那么getBlob转换成字节数组并发送到服务器
从sdcard阅读
List<Integer> drawablesId = new ArrayList<Integer>();
int picIndex=12345;
File sdDir = new File("/sdcard/pictures");
File[] sdDirFiles = sdDir.listFiles();
for(File singleFile : sdDirFiles)
{
Drawable.createFromPath(singleFile.getAbsolutePath());
/ you can create Bitmap from drawable
}
希望它能帮到你
答案 3 :(得分:1)
Android Asynchronous Http库提供了一种将文件上传到Web服务的方法。我在我的项目中使用它非常成功。
听起来您需要一个带有ID参数并返回文件的Web服务方法。您可以将blob存储在以ID索引的数据库表中,以便可以引用它们。
答案 4 :(得分:1)
不确定这是否是您想要的,但这将提交图像的方式与浏览器将图像作为表单的一部分提交的方式相同。您必须下载httmime-4.1.3.jar并将其作为项目中的引用库添加。
Bitmap bm;//whatever bitmap you are trying to send
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bm.compress(CompressFormat.JPEG, 75, bos);
byte[] data = bos.toByteArray();
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("http://yourwebsite.com/whatever");
ByteArrayBody bab = new ByteArrayBody(data, "image name");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("photo", bab);//"photo" is the name of the field that the image is submitted as.
postRequest.setEntity(reqEntity);
try {
HttpResponse response = httpClient.execute(postRequest);
} catch (ClientProtocolException e) {
Log.e("asdf", e.getMessage(), e);
} catch (IOException e) {
Log.e("asdf", e.getMessage(), e);
}