首页 > 代码库 > Java I/O基础

Java I/O基础

  字节流和字符流的区别,字节流一次读取一个字节,字符流一次读取的是一个Unicode码,读取了2个字节。

      可以以文本编辑器打开的可以使用字符流读取,否则用字符流读取可能就会出错。图像文件就需要用字节流读取,不能用字符流操作。

      字节流的基类是InputStream和OutputStream,字符流的基类是Reader和Writer。

      读取并复制图片的代码,读取到缓存,一边读一边写。 ps:文件的相对路径要写什么看看System.getProperty("user.dir")就知道了,这个是基础路径。   

public class FileIOTest {	public static void main(String [] args) throws IOException{				int BYTE_SIZE = 1;		int SAVE_SIZE = 1024;		int i = 0;		byte[] buff = new byte[BYTE_SIZE]; // 每次读的缓存		byte[] save = new byte[SAVE_SIZE]; // 保存前缓存			BufferedInputStream bf = new BufferedInputStream(new FileInputStream(new File("src/pattern/decorator/a.jpeg")));		FileOutputStream  fs = new FileOutputStream(new File("src/pattern/decorator/b.jpeg"));		while (bf.read(buff) != -1) { // 一个字节一个字节读		    save[i] = buff[0];		    if (i == SAVE_SIZE - 1) { // 达到保存长度时开始保存		     fs.write(save, 0, SAVE_SIZE);		     save = new byte[SAVE_SIZE];		     i = 0;		    } else {		     i++;		    		   }		   		   		}		// 最后这段如果没达到保存长度,需要把前面的保存下来		if (i > 0) {		   fs.write(save, 0, i);		}   				fs.close();		bf.close();	}}

   流的关闭应该放到finally中,上面的是不太合适的。

      

       下面是关于大文件读取的一些数据,原文为:

       http://aronlulu.iteye.com/blog/1018370

       读取文件大小:1.45G 
第一种,OldIO: 

Java代码  收藏代码
  1. public static void oldIOReadFile() throws IOException{  
  2.     BufferedReader br = new BufferedReader(new FileReader("G://lily_947.txt"));  
  3.     PrintWriter pw = new PrintWriter("G://oldIO.tmp");  
  4.     char[] c = new char[100*1024*1024];  
  5.     for(;;){  
  6.         if(br.read(c)!=-1){  
  7.             pw.print(c);  
  8.         }else{  
  9.             break;  
  10.         }  
  11.     }  
  12.     pw.close();  
  13.     br.close();  
  14. }  


耗时70.79s 


第二种,newIO: 

Java代码  收藏代码
  1. public static void newIOReadFile() throws IOException{  
  2.         FileChannel read = new RandomAccessFile("G://lily_947.txt","r").getChannel();  
  3.         FileChannel writer = new RandomAccessFile("G://newIO.tmp","rw").getChannel();  
  4.         ByteBuffer bb = ByteBuffer.allocate(200*1024*1024);  
  5.         while(read.read(bb)!=-1){  
  6.             bb.flip();  
  7.             writer.write(bb);  
  8.             bb.clear();  
  9.         }  
  10.         read.close();  
  11.         writer.close();  
  12.           
  13.     }  


耗时47.24s 


第三种,RandomAccessFile: 

Java代码  收藏代码
  1. public static void randomReadFile() throws IOException{  
  2.         RandomAccessFile read = new RandomAccessFile("G://lily_947.txt","r");  
  3.         RandomAccessFile writer = new RandomAccessFile("G://random.tmp","rw");  
  4.         byte[] b = new byte[200*1024*1024];  
  5.         while(read.read(b)!=-1){  
  6.             writer.write(b);  
  7.         }  
  8.         writer.close();  
  9.         read.close();  
  10.     }  


耗时46.65 

第四种,MappedByteBuffer: 

Java代码  收藏代码
  1. public static void mappedBuffer() throws IOException{  
  2.         FileChannel read = new FileInputStream("G://lily_947.txt").getChannel();  
  3.         FileChannel writer = new RandomAccessFile("G://buffer.tmp","rw").getChannel();  
  4.         long i = 0;  
  5.         long size = read.size()/30;  
  6.         ByteBuffer bb,cc = null;  
  7.         while(i<read.size()&&(read.size()-i)>size){  
  8.             bb = read.map(FileChannel.MapMode.READ_ONLY, i, size);  
  9.             cc = writer.map(FileChannel.MapMode.READ_WRITE, i, size);  
  10.             cc.put(bb);  
  11.             i+=size;  
  12.             bb.clear();  
  13.             cc.clear();  
  14.         }  
  15.         bb = read.map(FileChannel.MapMode.READ_ONLY, i, read.size()-i);  
  16.         cc.put(bb);  
  17.         bb.clear();  
  18.         cc.clear();  
  19.         read.close();  
  20.         writer.close();  
  21.           
  22.     }  


耗时:36 

前三种读法对应的资源占用图如下: 
相对于最后一种内存直接映射方式前面的测试其实无意义,基本秒杀。。。。。 
对于很大的文件直接分块映射时内存会不够,这是因为MappedByteBuffer未被释放造成的,sun未提供直接回收MappedByteBuffer区域的方法,这个时候有两种方法解决,第一种比较愚笨的: 

Java代码  收藏代码
  1.           System.gc();   
  2.          System.runFinalization();   
  3.          try {  
  4.     Thread.sleep(3000);  
  5. catch (InterruptedException e) {  
  6.       
  7.     e.printStackTrace();  
  8. }  


第二种网上找来的,利用反射调用clean方法: 

Java代码  收藏代码
  1. public static void unmap(final MappedByteBuffer buffer) {  
  2.         if (buffer == null) {  
  3.             return;  
  4.         }  
  5.         AccessController.doPrivileged(new PrivilegedAction<Object>() {  
  6.             public Object run() {  
  7.                 try {  
  8.                     Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);  
  9.                     if (getCleanerMethod != null) {  
  10.                         getCleanerMethod.setAccessible(true);  
  11.                         Object cleaner = getCleanerMethod.invoke(buffer, new Object[0]);  
  12.                         Method cleanMethod = cleaner.getClass().getMethod("clean", new Class[0]);  
  13.                         if (cleanMethod != null) {  
  14.                             cleanMethod.invoke(cleaner, new Object[0]);  
  15.                         }  
  16.                     }  
  17.                 } catch (Exception e) {  
  18.                     e.printStackTrace();  
  19.                 }  
  20.                 return null;  
  21.             }  
  22.    
  23.         });  
  24.     }  


以上两种方法感觉都别扭,还有就是可以自己分割成物理文件再循环调用,这个也不太美观。 
速度也会减慢好多。

Java I/O基础