私はバイト配列に3ギガバイトのファイルを変換しようとしているが、OOMを取得しています(OutOfMemoryError
)。
我々は試してみました
RandomAccessFile randomAccessFile = new RandomAccessFile(sourceLocation.getAbsolutePath(), "r");
MappedByteBuffer mappedByteBuffer = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length()); //while it is large file, it threw 'mmap failed: ENOMEM (Out of memory)' exception.
byte[] data = new byte[1024 * 1024]; // 1MB read at time
while (mappedByteBuffer.hasRemaining()) {
int remaining = data.length;
if (mappedByteBuffer.remaining() < remaining)
remaining = mappedByteBuffer.remaining();
mappedByteBuffer.get(data, 0, remaining);
}
mappedByteBuffer.rewind();
byte fileContent[] = mappedByteBuffer.array(); //while it is small file, it threw 'java.nio.ReadOnlyBufferException' exception.
randomAccessFile.close();
}
私の独自のリクエストボディ:カスタムリクエストボディクラス私のリクエストボディを用意
import android.os.Looper;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
public class ProgressRequestBodyTemp extends RequestBody
{
private static final int DEFAULT_BUFFER_SIZE = 2048;
private File mFile;
private String mPath;
private String mFileType;
private int mItemIndex;
private UploadCallbacks mListener;
private byte[] encryptedData;
private ByteArrayInputStream bis;
public ProgressRequestBodyTemp(final String fileType, final File file, byte[] encryptedData, final int itemIndex, final UploadCallbacks listener)
{
this.mFile = file;
this.mFileType = fileType;
this.mItemIndex = itemIndex;
this.mListener = listener;
this.encryptedData = encryptedData;
try
{
bis = new ByteArrayInputStream(encryptedData); // Convert byte array into input stream for send data to server
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
@Override
public MediaType contentType()
{
try
{
return MediaType.parse(mFileType);
}
catch (Exception ex)
{
return MediaType.parse("");
}
}
@Override
public long contentLength() throws IOException
{
return encryptedData.length;
}
@Override
public void writeTo(BufferedSink sink) throws IOException
{
long fileLength = mFile.length();
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long uploaded = 0;
try
{
int read;
android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
while ((read = bis.read(buffer)) != -1)
{
// update progress on UI thread
handler.post(new ProgressUpdater(uploaded, encryptedData.length));
uploaded += read;
sink.write(buffer, 0, read);
}
}
finally
{
bis.close();
}
}
public interface UploadCallbacks
{
void onProgressUpdate(int itemIndex, int percentage);
}
private class ProgressUpdater implements Runnable
{
private long mUploaded;
private long mTotal;
public ProgressUpdater(long uploaded, long total)
{
mUploaded = uploaded;
mTotal = total;
}
@Override
public void run()
{
if (mListener != null)
{
mListener.onProgressUpdate(mItemIndex, (int) (100 * mUploaded / mTotal));
}
}
}
}
私の要求:アップロードファイルの要求
File sourceLocation = new File(".....");
byte fileContent[] = .... // byte array
ProgressRequestBody requestFile = new ProgressRequestBody(fileType, sourceLocation, fileContent, itemIndex, this);
MultipartBody.Part body = MultipartBody.Part.createFormData("file", sourceLocation.getName(), requestFile); // MultipartBody.Part is used to send also the actual file name
Call<String> mediaCall = getRetrofit().addMedia("SOME STRING DATA", body);
それは与えているOutOfMemoryError
、バイト配列に大きなファイルを変換するための最良の方法を提案してください。
すべてのヘルプは、多くのことを感謝しています。前もって感謝します。
使用InputStream
してOutputStream
。
あなたはデータの3ギガバイトと協力し、それをメモリにロードすることはできませんとき、彼らは、例えば、データの大きな量のために意図されています。
あなたがファイルをアップロードしようとしている場合は、使用FileInputStream
。作成しFile
、オブジェクトをに渡しFileOutputStream
コンストラクタとそのからのバイトの読み込みを開始InputStream
するbyte[]
バッファとでバイトを送信するOutputStream
サーバへ。
このアプローチは発生しませんOutOfMemoryError
あなたが約あるべきバッファ、いっぱいに必要なだけのバイトを読んでいるので、8キロバイト- 2キロバイトのサイズのを。バッファがいっぱいになった後は、サーバーにバイトを書き込みます。バッファがサーバに書き込まれた後、再度、バッファに読み込まれ、プロセスはファイル全体がアップロードされるまでにいっています。
FileInputStreamのを使用して実施例
File file = new File("yourfile.txt");
FileInputStream fis = null;
OutputStream outputStream = null;
url = new URL(desiredUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try {
fis = new FileInputStream(file);
connection.setDoOutput(true);
outputStream = connection.getOutputStream();
int actuallyRead;
byte[] buffer = new byte[2048];
while ((actuallyRead = fis.read(buffer)) != -1) {
//do something with bytes, for example, write to the server
outputStream.write(buffer);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
try {
if (outputStream != null)
outputStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
注:この方法では、サーバーにバッファがいっぱいになるたびに再接続する必要が意味するものではありません。それはファイルの処理が完了するまで、それは継続的に、サーバに書き込みます。これは、同じ、単一の接続の下にあるすべてが起こるのだろう。