由于单个文件较大,将文件进行分割,然后上传到服务端,服务端进行拼接,结果开始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();

解决方案 »

  1.   

    不是大文件的问题,是conn.getOutputStream()流没有进行清空
      

  2.   

      if ((count + 1) % (20 * 1024) == 0) {//每20M
      

  3.   

    请尝试修改以下代码                                if (length != temp.length) {
                                        _temp = new byte[length];//每次都分配一个1K的对象会不会引起问题?
                                        System.arraycopy(temp, 0, _temp, 0, length);
                                        temp = _temp;
                                    }
                                    out.write(temp);修改为                                /*if (length != temp.length) {
    _temp = new byte[length];
    System.arraycopy(temp, 0, _temp, 0, length);
    temp = _temp;
    }*/
    out.write(temp,0,length);
      

  4.   


    if ((count + 1) % (20 * 1024) == 0) {//每20M
    ·······
     count += length;
      

  5.   

     if (length != temp.length) {
                                        _temp = new byte[count];
                                        System.arraycopy(temp, 0, _temp, 0, length);
                                        temp = _temp;
                                    }
      

  6.   

    哦,我写错了!直接修改while末尾的 count++ 为 count += length,就没问题了!开始的判断
    if ((count + 1) % (20 * 1024) == 0) {//每20M
    在你代码中count每次+1,当然会内存溢出哦!
      

  7.   

    count代表循环的次数,每次上传1k,20*1024次说明是20M,这个不会溢出,是流里面东西没有清除的原因,我DEBUG看了内存使用率,每次想流中write的时候内存就会变大,但是最后flush和close时候都没有进行清空
      

  8.   


    按照你的意思,那count要迭代20 * 1024次才上传一次哦,是我没看懂还是你写错了哦!