Загрузить файл в Android с ошибкой вне памяти - PullRequest
0 голосов
/ 12 марта 2012

Мой код загрузки, как показано ниже:

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 мб, загрузка будет неудачной и покажет ошибку OutOfMemory.Я думаю, что это вызвано путем помещения всех данных в буфер.Поэтому я хочу сделать это для отправки данных в то время как буфер сохраняет 1024 байта.Но я понятия не имею, чтобы сделать это.Может ли кто-нибудь помочь мне сделать это?

Ответы [ 2 ]

2 голосов
/ 10 августа 2012

Брайан, вы должны добавить

con.setChunkedStreamingMode(0);

до

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

, если ваш сервер может поддерживать чанк-режим, или добавить

con.setFixedLengthStreamingMode(packet_size);

, где packet_size = upload_file_size + header_size.

1 голос
/ 12 марта 2012

Вы должны подтвердить, в какой момент происходит ваша ошибка.Я подозреваю, что это во время чтения ответа.В этом случае кажется, что сервер может отвечать большим количеством данных, которые вы помещаете в StringBuffer.Вам действительно нужно потреблять весь ответ и хранить его в памяти?Если это файл, сохраните его, а не храните в памяти.


Я провел еще несколько исследований, и вот еще одна возможность.Android JVM по умолчанию имеет максимальную кучу 16 МБ.См. 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();
  }
}
...