5、Java中的IO

IO是Java及众多编程语言很重要的一块,同时很多程序的瓶颈和耗时操作也都在IO这块。所以能够很好的解决IO问题对提高程序性能有很大的帮助!本章我们将要系统的对Java IO做个分析,通过理论加实践,希望能真正彻底的理解并且掌握了它。

一、简介

IO操作面临很多问题,信息量的巨大,网络的环境等等,因为IO不仅仅是对本地文件、目录的操作,有时对二进制流、还有一部分是网络方面的资源,所以多种原因直接造成IO操作无疑是耗时且复杂多变的。Java对IO的支持是个不断的演变过程,经过了很多的优化,直到JDK1.4以后,才趋于稳定,在JDK1.4中,加入了nio类,解决了很多性能问题,虽然我们有足够的理由不去了解关于Java IO以前的情况,但是为了学好现在的类,我们还是打算去研究下,通过掌握类的优化情况来彻底理解IO的机制!Java IO主要主要在java.io包下,分为四大块近80个类:

1、基于字节操作的I/O接口:InputStream和OutputStream

2、基于字符操作的I/O接口:Writer和Reader

3、基于磁盘操作的I/O接口:File

4、基于网络操作的I/O接口:Socket(不在java.io包下)

影响IO性能的无非就是两大因素:数据的格式及存储介质,前两类主要是数据格式方面的,后两个类是地址方面的:本地和网络。所以策划好这两个方面的活动,有助于我们合理使用IO。

 

二、基于字节的I/O操作(InputStream和OutputStream)

我们先来看看类图:

public abstract class InputStream extends Object implements Closeable

图1

图2

二者类似,我只详细讲解InputStream类,OutputStream留给大家自己去学习。InputStream类是个抽象类,里面核心的方法就是read()、read(byte b[])、read(byte b[], int off, int len),这三个方法是用于读取数据的底层的方法,他们可以用来读取以下这些类型的数据:

A. 字节数、B. String对象、C. 文件、D. 管道,从一端进入,从另一端输出、E. 流、F. internet资源

每一种数据源都有相应的InputStream子类,因为InputStream是个处于顶层的类,用来处理各种数据源的类都继承了InputStream类,我们来看看这些类:

ByteArrayInputStream:处理字节数组的类,允许将内存的缓冲区当做InputStream使用。

StringBufferInputStream:将String转换成InputStream,内部实现用的是StringBuffer。

FileInputStream:从文件中读取数据。

PipedInputStream:用于从管道中读取数据。

SequenceInputStream:将多个流对象转化成一个InputStream。

FilterInputStream:装饰器类,为其它InputStream类提供功能。

 

 

做过关于IO操作的读者知道,我们很少单独使用哪个类来实现IO操作,平时都是几个类合起来使用,这其实体现了一种装饰器模式(详见:http://blog.csdn.net/zhangerqing)的思想,在后面的分析中我们会详细的分析。从上面的图1中我们可以看出,FilterInputStream虽说是Inputstream的子类,但它依然是BufferedInputStream、DataInputStream、LineNumberInputStream、PushbackInputStream类的父类,这四个类分别提供了最贴近我们程序员使用的方法,如:readInt() 、readLine()、readChar()等等。对于IO操作,不管是磁盘还是网络,最终都是对字节的操作,而我们平时写的程序都是字符形式的,所以在传输的过程中需要进行转换。在字符到字节的转换过程中,我们需要用到一个类:InputStreamReader。

三、基于字符的I/O操作(Writer和Reader)

图3

图4

Writer和Reader操作的目的就是操作字符不是字节,和InputStream和OutputStream配合增加IO效果。通过InputStreamReader和OutputStreamReader可以进行字节和字符的转换,设计Writer和Reader的目的是国际化,使IO操作支持16位的Unicode。

四、基于磁盘的I/O操作(File)

五、基于网络的I/O操作(Socket)

六、NIO

七、经典IO操作

 Library:1、从本地字符流文件(绝对、相对)地址读取文件

 

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.StringReader;
class InputStreamTest {   
    public static String read(String filename) throws Exception {  
        BufferedReader br = new BufferedReader(new FileReader(filename));   //Reader实例
        String s;  
        StringBuffer sb = new StringBuffer();  
        while ((s = br.readLine()) != null) {  
            sb.append(s + "\n");  
        }  
        br.close();  
        return sb.toString();  
    }
}//sb就是文件的字符串,下面将其一个一个读出
public class MemoryInput {  
    public static void main(String[] args) throws Exception {  
        StringReader in = new StringReader(  
                InputStreamTest.read("../ReaderStream/wwww.txt"));  
        int c;  
        while ((c = in.read()) != -1)  
            System.out.print((char) c+"  ");  
    }  
}  
 2、 System.in System.out

System.in返回的是未经包装的InputStream对象,所以需要进行装饰,经InputStreamReader转换为Reader对象,放入BufferedReader的构造方法中。除此之外,System.outSystem.err都是直接的PriintStream对象,可直接使用。

public final class System {
    public final static InputStream in = null;
    public final static PrintStream out = null;
    public final static PrintStream err = null;
    private static volatile SecurityManager security = null;
public abstract class InputStream implements Closeable {
public class PrintStream extends FilterOutputStream
    implements Appendable, Closeable
{
public void println() {
        newLine();
    }
public void print(int i) {
        write(String.valueOf(i));       //class Writer.writer(String)   write(str, 0, str.length());
    }
  private void newLine() {
        try {
            synchronized (this) {

也可以使用java.util包下的Scanner类来实现上述程序;

3、读取二进制文件

public class BinaryFile {  
    /* the parameter is a file */  
    public static byte[] read(File file) throws IOException {  
        BufferedInputStream bf = new BufferedInputStream(new FileInputStream(  
                file));  
        try {  
            byte[] data = new byte[bf.available()];  
            bf.read(data);  
            return data;  
        } finally {  
            bf.close();  
        }  
    }  
    /* the param is the path of a file */  
    public static byte[] read(String file) throws IOException {  
        return read(new File(file).getAbsoluteFile());  
    }  
    public static void main(String[] args) throws IOException{
    	 byte[] a=BinaryFile.read("E:/jsL/20130415161705906.jpg");
    String s=new String(a);
    System.out.println(s+a.length);
    }
}  
读出来的都是乱码

4、单个文件复制(边读编写)

public class CopyBinaryFile{
	//private static final int MAX_SKIP_BUFFER_SIZE = 2048;
	public  static void copyFile(String oldPath,String newPath) throws IOException{
		File oldfile=new File(oldPath);
		if(oldfile.exists()){
			FileInputStream  inf=new FileInputStream(oldPath);  
			FileOutputStream outf=new FileOutputStream(newPath);
			byte[] b=new byte[1024];
			int length=0;
			while((length=inf.read(b))>0){
				outf.write(b, 0, length);          //边读边写
			}
			inf.close();	
                        outf.close();
		}
	}	
	public static void main(String...args) throws IOException{
		String oldPath="E:/jsL/20130415161705906.jpg";
		String newPath = "e:/jsl/sb.jpg";
		copyFile(oldPath,newPath);
	}
}

 5、文件目录复制(太慢)

package springc;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class CopyBinaryFolder {
	public static  void copyFolder(String oldPath,String newPath) {
		try{
			new File(newPath).mkdirs();  //新建文件目录(会自行判断是否存在)
			File oldfile=new File(oldPath);
			String[] context=oldfile.list();
			File temp=null;
			for(int x=0;x<context.length;x++){
				if(oldPath.endsWith("/")){
					temp=new File(oldPath+context[x]);
				}else{
					temp=new File(oldPath+"/"+context[x]);
				}
				if(temp.isFile()){
					FileInputStream inf=new FileInputStream(temp);
					FileOutputStream outf=new FileOutputStream(newPath+"/"+temp.getName().toString());
					byte[] buffer=new byte[1024*5];
					int l=0;
					while((x=inf.read(buffer))>0){
						outf.write(l);
					}
					inf.close();
					outf.close();
				}else if(temp.isDirectory()){
					copyFolder(oldPath+"/"+context[x], newPath+"/"+context[x]);
				}
			}
		}
		catch(Exception e){
			System.out.println("复制出现异常");
			try {
				throw e;
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}
	public static void main(String...strings){
		System.out.println("复制中。。。");
		copyFolder("E:/jsL/new1/","E:/jsL/new2");
		System.out.println("复制完成!");
	}
}

 6、文件管道复制(较快)

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class CopyChannelFile {
	public static void fileChannelCopy(String oldfile,String newfile) {
		FileInputStream fi=null;
		FileOutputStream fo =null;
        FileChannel in = null;
        FileChannel out = null;
        try {
        	fi = new FileInputStream(new File(oldfile));
        	fo = new FileOutputStream(new File(newfile));
            in = fi.getChannel();//得到对应的文件通道
            out =fo.getChannel();//得到对应的文件通道
            in.transferTo(0, in.size(), out);//连接两个通道,并且从in通道读取,然后写入out通道
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fi.close();
                in.close();
                fo.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	static void exeChannel(String oldfile,String newfile) throws InterruptedException{
		long start,end;
		start=System.currentTimeMillis();
		System.out.println(start);
		fileChannelCopy(oldfile,newfile);
		end=System.currentTimeMillis();
		System.out.println("管道耗时:"+(end-start)+"ms");  //没有打印,不过很快		
	}
	static void exeStream(String oldfile,String newfile) throws IOException{
		long start,end;
		CopyBinaryFile f=new CopyBinaryFile();
		start=System.currentTimeMillis();
		f.copyFile(oldfile, newfile);
		end=System.currentTimeMillis();
		System.out.println("输出流耗时:"+(end-start)+"ms");
		
	}
	public static void main(String...s) throws IOException{		
		fileChannelCopy("F:G/test.pdf","E:/jsL/new1/test.pdf"); //74M
	//	exeStream("F:G/test.pdf","E:/jsL/new1/test.pdf");
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

l

猜你喜欢

转载自nickfover.iteye.com/blog/2117199