/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.common; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import jef.common.log.LogUtil; import jef.tools.IOUtils; /** * 用于缓存数据的对象。当数据小于2M时,自动使用内存中的空间 * 大于2M时,使用文件 * @author Administrator * */ public class BigDataBuffer extends OutputStream { public static final int memcacheLength=2*1024*1024; //内存缓存数据最大2M private static final int RECEIVE_MEM=-1; //正在收取数据,使用缓存 private static final int RECEIVE_FILE=0; //正在收取数据,使用文件 private static final int OPEN_MEM=-2; //已就绪可放出数据,使用缓存 private static final int OPEN_FILE=1; //已就绪可放出数据,使用文件 private static final int CLOSED=2; //数据已经取走,无法再利用 private int state; //当前状态,为上述之一 long length;//当前长度 ByteBuffer memCache; private File file; private FileOutputStream out;//存储位置:文件,仅当RECEIVE_FILE时有效 private InputStream output; //获取方式:流:仅当OPEN_FILE时有效 /** * 构造 */ public BigDataBuffer(){ state=RECEIVE_MEM; memCache=ByteBuffer.allocate(memcacheLength); } private BigDataBuffer(byte[] data){ state=RECEIVE_MEM; memCache=ByteBuffer.wrap(data); } /** * 写入内容 * @param clientBuffer * @throws IOException */ public void write(ByteBuffer clientBuffer) throws IOException { write(clientBuffer.array(),0,clientBuffer.limit()); } /** * 写入内容 * @param buffer * @throws IOException */ public void write(byte[] buffer) throws IOException{ write(buffer,0,buffer.length); } public void write(int b) throws IOException { if(state==RECEIVE_MEM){ if(length+1<=memCache.capacity()){ memCache.put((byte)b); length++; return; }else{ createFile();//将内存缓存写入磁盘 } } if(state!=RECEIVE_FILE){ throw new IllegalStateException("The BigDataBuffer do not allow write any data, state="+state); } out.write(b); length++; } /** * 写入内容 * @param buffer * @throws IOException */ public void write(byte[] buffer,int off,int len) throws IOException{ if(state==RECEIVE_MEM){ if(length+len<=memCache.capacity()){ memCache.put(buffer, off, len); length+=len; return; }else{ createFile();//将内存缓存写入磁盘 } } if(state!=RECEIVE_FILE){ throw new IllegalStateException("The BigDataBuffer do not allow write any data, state="+state); } out.write(buffer,off,len); length+=len; } /** * 标记状态为收取结束,开始利用数据 */ public void flip(){ if(state==RECEIVE_MEM){ memCache.flip(); state=OPEN_MEM; } if(state==RECEIVE_FILE){ IOUtils.closeQuietly(out); state=OPEN_FILE; } } class InnerInputStream extends FilterInputStream{ protected InnerInputStream(InputStream in) { super(in); } @Override public void close() throws IOException { super.close(); clear(); } @Override public String toString() { StringBuilder sb=new StringBuilder("Buffer:"); sb.append(length).append(" bytes"); return sb.toString(); } } /** * 写入完成,开始获取内容 * @return * @throws IOException */ public InputStream getAsStream() throws IOException{ flip(); if(state==OPEN_MEM){ if(output==null){ memCache.rewind(); output=new InnerInputStream(new ByteBufferInputStream(memCache)); } return output; } if(state==OPEN_FILE){ if(output==null)output=new InnerInputStream(new FileInputStream(file)); return output; } throw new IllegalStateException("Current state is "+ state); } /** * 清空对象,可以进行下一次收取数据操作 */ public void clear(){ if(state==RECEIVE_MEM || state==OPEN_MEM){ memCache.clear(); return; } if(state==RECEIVE_FILE){ IOUtils.closeQuietly(out); state=OPEN_FILE; } if(state==OPEN_FILE){ if(file.exists())file.delete(); file=null; state=RECEIVE_MEM; } length=0; } private void createFile(){ try { file=File.createTempFile("~temp", ".buf"); out=new FileOutputStream(file); memCache.flip(); out.getChannel().write(memCache); memCache.clear();//不再使用的内存区域 state=RECEIVE_FILE; } catch (FileNotFoundException e) { LogUtil.exception(e); } catch (IOException e) { LogUtil.exception(e); } } /** * 读取部分数据 * @param buff * @param offset * @param len */ public void putByte(byte[] buff, int offset, int len){ System.arraycopy(memCache.array(), offset, buff, 0, len); } /** * 返回数据总长度 * @return */ public long length() { return this.length; } /** * 从文件形成 * @param file * @return */ public static BigDataBuffer wrap(File file){ BigDataBuffer bb=new BigDataBuffer(); bb.state=OPEN_FILE; bb.file=file; bb.length=file.length(); return bb; } /** * 从内存数据形成 * @param data * @return */ public static BigDataBuffer wrap(byte[] data){ BigDataBuffer bb=new BigDataBuffer(data); return bb; } /** * 从流形成,流会自动关闭 * @param in * @return * @throws IOException */ public static BigDataBuffer wrap(InputStream in){ BigDataBuffer bb=new BigDataBuffer(); byte[] buf=new byte[1024]; try{ int n; while((n=in.read(buf))>-1){ bb.write(buf,0,n); } IOUtils.closeQuietly(in); }catch(IOException e){ throw new RuntimeException(e.getCause()); } return bb; } /** * 如果缓存是在内存,也以文件的形式返回。 * @return */ public File toFile() { if(state==RECEIVE_MEM){ createFile(); } if(state==OPEN_MEM){ memCache.rewind(); createFile(); } if(state==RECEIVE_FILE){ IOUtils.closeQuietly(out); state=OPEN_FILE; } if(state==OPEN_FILE){ return file; } throw new UnsupportedOperationException(); } /** * 如果缓存是文件,则返回,否则返回null; * @return */ public File getTmpFile(){ return file; } public void close() throws IOException { flip(); } }