日期:2014-05-20  浏览次数:20880 次

URLConnection上传文件越来越卡,最后内存溢出
由于单个文件较大,将文件进行分割,然后上传到服务端,服务端进行拼接,结果开始100M速度还行,后来越来越慢,最后就内存溢出了,眼拙没看错来哪里出了问题,求指点,代码如下:
客户端代码:


URL serverURL = new URL(url);
//支持多文件上传
for(int i=0;i<files.length;i++)
{
URLConnection conn = null;
//每次重新打开连接
try {
conn = serverURL.openConnection();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("无法连接到服务器");
}
//相同文件上传的头信息都相同
int cutIndex = 1;//拆分数量
conn.setRequestProperty("cc", "zc");
conn.setRequestProperty("dirXh", dirxh);
conn.setRequestProperty("wdxh", (String)ret.get(i));
conn.setRequestProperty("cutIndex", "1");
conn.setRequestProperty("opr", "" + Constant.DOC_UPLOAD);
conn.setDoInput(true);
conn.setDoOutput(true);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(files[i]));
BufferedOutputStream out = new BufferedOutputStream(conn.getOutputStream());

byte[] temp = new byte[1024];
byte[] _temp = null;
int length = -1;
/** 由于outputStream不是一个网络流,读取的数据没有立即传输到服务端,而是存储在内存中,
 * 等读取完之后再写到服务端,所以单个文件过大会导致JVM内存溢出,
 * 所以此处通过对文件进行分割,每次传输20M(20*1024*1024byte),将分割信息记录到头信息中
 * 在服务端对信息再进行拼装 */
int count = 0;
while ((length = in.read(temp)) != -1){
if ((count + 1) % (20 * 1024) == 0) {//每20M
out.flush();
out.close();
out = null;
InputStream inputStream = conn.getInputStream();
inputStream.close();
inputStream = null;
conn = null;
try {
conn = serverURL.openConnection();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("无法连接到服务器");
}
//一次上传的头信息都相同
conn.setRequestProperty("cc", "zc");
conn.setRequestProperty("dirXh", dirxh);
conn.setRequestProperty("wdxh", (String)ret.get(i));
conn.setRequestProperty("cutIndex", "" + (++cutIndex));
conn.setRequestProperty("opr", "" + Constant.DOC_UPLOAD);
conn.setDoInput(true);
conn.setDoOutput(true);
out = new BufferedOutputStream(conn.getOutputStream());
}
if (length != temp.length) {
_temp = new byte[length];
System.arraycopy(temp, 0, _temp, 0, length);
temp = _temp;
}
out.write(temp);
count ++;
}
out.flush();
out.close();
out = null;
in.close();
//为什么要读取服务端的返回信息时服务端才认定客户端的传输已经结束?
InputStream inputStream = conn.getInputStream();
inputStream.close();
inputStream = null;
}


服务端代码:

String absolutePath=DocManager.getAbsolutePath(dirXh);
RandomAccessFile file = new RandomAccessFile(new File(absolutePath + "/" + wdxh), "rw");
byte[] temp = new byte[1024];
byte[] _temp = null;
int length = -1;
while ((length = in.read(temp)) != -1) {
if (length != temp.length) {
_temp = new byte[length];
System.arraycopy(temp, 0, _temp, 0, length);
temp = _temp;
}
                                //拼接文件
file.seek(file.length());
file.write(temp);
}
file.close();
in.close();

------解决方案--------------------
实际上,你还是在内存中对大文件进行切分的。

可以这样做,先做切分工作,将大文件分成小文件保存在硬盘中;
然后再依次读取做上传工作
每次上传成功后,还可以写个日志文件,记录上传的小文件序号,以便做到断点续传的功能。

最后全部上传成功后,在服务器端合并。
------解决方案--------------------
  if ((count + 1) % (20 * 1024) == 0) {//每20M
------解决方案--------------------
请尝试修改以下代码

                                if (length != temp.length) {