使用outofmemory错误在Android上传文件

时间:2012-03-12 01:50:52

标签: android upload out-of-memory

我的上传代码如下:

String end = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
try {
URL url = new URL(ActionUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestMethod("POST");
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Accept", "text/*");
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
DataOutputStream ds = new DataOutputStream(con.getOutputStream());
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data;" + "name=\"folder\"" + end + end);
ds.write(SavePath.getBytes("UTF-8"));
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data;" + "name=\"Filedata\"; filename=\"");
ds.write(FileName.getBytes("UTF-8"));
ds.writeBytes("\"" + end);
ds.writeBytes(end);
FileInputStream fStream = new FileInputStream(uploadFilepath+""+FileName);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int length = -1;
int pro = 0;
while((length = fStream.read(buffer)) != -1) {
ds.write(buffer, 0, length);
}       
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
fStream.close();
ds.flush();
InputStream is = con.getInputStream();
int ch;
StringBuffer b = new StringBuffer();
while((ch = is.read()) != -1) {
b.append((char)ch);
}
ds.close();
}
catch(Exception e) {
e.printStackTrace();
}

上传较小的文件时可以正常工作。 但是,当更多16 MB,它将上传失败并显示OutOfMemory错误。 我认为这是因为将所有数据放入缓冲区。 所以我想让它在缓冲区保存1024字节时发送数据。 但我不知道那样做。 愿任何人帮我做吗?

2 个答案:

答案 0 :(得分:2)

brian,你应该添加

con.setChunkedStreamingMode(0);

之前

DataOutputStream ds = new DataOutputStream(con.getOutputStream());

如果您的服务器可以支持分块模式,或添加

con.setFixedLengthStreamingMode(packet_size);

其中packet_size = upload_file_size + header_size

答案 1 :(得分:1)

您应该确认您的错误发生在什么时候。我怀疑这是在阅读回复期间。在这种情况下,似乎服务器可能正在响应您放在StringBuffer中的大量数据。你真的需要消耗整个响应并将其保存在内存中吗?如果它是一个文件,请保存它而不是保留在内存中。


我做了更多的研究,这是另一种可能性。 Android JVM默认最大堆容量为16mb。有关详细信息,请参阅this

另一方面,如果您的服务器实际上没有使用数据,那么大部分数据都将驻留在客户端上。因此,如果您拥有超过最大数据堆,则客户端将失败。

所以我怀疑你的服务器只是没有从流中读取数据。

以下类(代码的相关部分的片段)说明了问题。在任何JVM上运行它,如下所示:

java -Xmx16m -cp . Test

它会很快产生OOM。事实上,比预期的要早得多。

import java.io.*;
import java.net.*;

public class Test {
  public static void main(String argv[]) throws Exception {
    new Thread() {
      public void run() {
        try {
           new ServerSocket(12000).accept();
        } catch (Throwable t) {
          t.printStackTrace();
        } 
      }
    }.start();

    URL url = new URL("http://localhost:12000/");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setDoInput(true);
    con.setDoOutput(true);
    con.setUseCaches(false);
    DataOutputStream ds = new DataOutputStream(con.getOutputStream());
    int bufferSize = 1024;
    byte[] buffer = new byte[bufferSize];
    for (int i=0;i<100000;i++) {
      ds.write(buffer, 0, 1024);
      System.out.println("Written chunk " + i);
    }       
    ds.flush();
  }
}