Java的I/O操作

一、概述

  Java的IO支持通过java.io包下的类和接口来完成,在java.io包下主要有包括输入、输出两种IO流,每种输入输出流又可分为字节流和字符流两大类。从JDK1.4以后,Java在java.nio包下提供了系列的全新API,通过java.nio,程序可以更高效的进行输入、输出操作。

二、Java I/O类和接口 

  1. File类

  File类直接处理文件和文件系统,它没有指定如何获取信息或将信息保存到文件中,只描述了文件本身的属性。File对象用于获得或者操作与磁盘文件相关联的信息,如存取权限、时间、日期和目录路径等,并且还可以浏览子目录的层次结构。

下面的构造函数可用来创建File对象:

构造方法摘要
File(File parent, String child)
          根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File(String pathname)
          通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
File(String parent, String child)
          根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(URI uri)
          通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例。

  File类定义了许多可以得到File对象标准属性的方法

public class Demo
{
    public static void main(String[] args)
    {
        File f=new File("D://hello.java");
        System.out.println(f.getParent());//返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null
        System.out.println(f.getName());//返回由此抽象路径名表示的文件或目录的名称
        System.out.println(f.exists());//测试此抽象路径名表示的文件或目录是否存在
        System.out.println(f.getAbsoluteFile());// 返回此抽象路径名的绝对路径名形式
        System.out.println(f.getAbsolutePath());//返回此抽象路径名的规范路径名字符串
        System.out.println(f.getPath());//将此抽象路径名转换为一个路径名字符串
        System.out.println(f.hashCode());//计算此抽象路径名的哈希码
        System.out.println(f.length());//返回由此抽象路径名表示的文件的长度
        System.out.println(f.list());// 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录
        System.out.println(f.mkdir());//创建此抽象路径名指定的目录
    }
}

  2. 流类

  Java中把不同的输入输出源抽象画为“流”,通过流的方式允许?Java程序使用相同的方式来访问不同的输入输出源。

  字节流类:提供了处理针对字节的IO的丰富环境,顶部类是InputStream和OutputStream,它们均是抽象类。

  字符流类:字节流类不能处理Unicode字符,字符流类操作的数据单元为字符,,顶部类是Reader和Writer。

  字节流类和字符流类的功能基本一样,只是操作的数据单元不同,其中InputStream和Reader都是将数据抽象为一根水管,程序可以通过read()方法每次抽取一个“水滴”,也可以通过read(char[] cbuf)方法来读取多个“水滴”,程序通过read()方法返回-1来判断是否到了输入流的结束点。

  eg.读取文件,统计文件字符数:

public class FileDemo
{
    public static void main(String[] args)
    {
        int b=0;
        try
        {
            FileInputStream in=null;
            in =new FileInputStream("D:\\a.txt");
            long num=0;
            while((b=in.read())!=-1)
            {
                System.out.print((char)b);
                num++;
            }
            in.close();    
            System.out.println(num);
        } 
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        
    }
}

  FileInputStream类创建一个InputStream,可以用来从文件中读取文件。

  eg.将一个文件内容拷贝至另一个文件:

public class FileOutStream
{
    public static void main(String[] args)
    {
        int b=0;
        try
        {
            FileInputStream in =new FileInputStream("D:\\Eclipse\\workSpace\\day_041602\\src\\day_041602\\TestMain.java");
            FileOutputStream out=new FileOutputStream("D:\\hello.java");
            while((b=in.read())!=-1)
            {
                out.write(b);
            }
            in.close();
            out.close();
            System.out.println("执行完成");
        } 
        catch (FileNotFoundException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

  BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter称为缓冲流,它们通过缓冲输入输出来提高性能。

  eg.在hello.java文本中输入100个随机数,并在屏幕上显示:

public class BufferWriterDemo
{
    public static void main(String[] args)
    {
        try
        {
            String s;
            BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\hello.java"));
            BufferedReader br=new BufferedReader(new FileReader("D:\\hello.java"));
            for(int i=0;i<100;i++)
            {
                s=String.valueOf(Math.random());  //产生随机数
                bw.write(s);//写入hello.java文件中
                bw.newLine();//写入一个换行符
            }
            bw.flush();//刷新缓冲
            while((s=br.readLine()) != null)//读取一个文本行
                {
                        System.out.println(s);
                }
            bw.close();
            br.close();
        } 
        catch (IOException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

 三、NIO

  1.概述

  NIO使用内存映射的方式处理输入输出,将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了。

  相关的包有:java.nio.channels包:主要包含Channel和Selector相关的类,java.nio.charset包:主要包含和字符集相关的类

  NIO系基于两个基本的元素:缓冲和通道。缓冲区容纳数据,通道代表队I/O设备的开放式连接。一般而言使用NIO系统,需要获得到I?O设备的一个通道和容纳数据的一个缓冲区,然后可以对缓冲区进行操作,随意输入和输出数据。除此之外,NIO还提供了用于将Unicode字符串映射成字节序列以及逆映射操作的Charset类,还有支持非阻塞式输入输出的Selector类。

  2.缓冲区

   缓冲(buffer)可以理解成一个容器,它的本质是一个数组,发送到Channel中的所有对象都必须首先放到buffer中,从channel中读取的数据也必须先读到buffer中。

   Buffer中有三个重要的参数:

    • capacity:表示该Buffer的最大存储容量
    • limit:第一个不应该被读出或写入的缓冲区位置索引
    • position:用于指明下一个可以被读出或写入的缓冲区位置索引

    除此之外还有一个可选的mark标记,该mark允许程序直接将position定位到mark处。位置如下所示:

  

    每放入一个数据,position向后移动一位,当Buffer装入数据结束后,调用flip方法,将limit设置为position所在的位置,将position设置为0,这样使得从Buffer中读数据总是从0开始。当Buffer输出数据结束后,Buffer调用 clear方法,它将position置为0,,置limit为capacity,这样为再次向Buffer中装入数据做好准备。Buffer还提供了put和get方法,用于向Buffer中放入数据和读取数据,既支持对单个数据的访问也支持对批量数据的访问。

  eg.

public class Test
{
    public static void main(String[] args)
    {
        CharBuffer m=CharBuffer.allocate(8);
        m.put('a');
        m.put('b');
        m.put('c');
        System.out.println("position:"+m.position());
        System.out.println("limit:"+m.limit());
        m.flip();
        System.out.println("第一个元素"+m.get());
        System.out.println("第二个元素"+m.get());
        System.out.println("position:"+m.position());
    }
}

   执行结果:

  

  3.通道

   Channel与传统的InputStream、OutputStream最大的区别在于它提供了一个map方法,通过该map方法可以直接将一块数据映射到内存中。

     Channel是一个接口,系统为该接口提供了FileChannel等实现类,所有的Channel都是通过传统节点InputStream、OutputSteam的getChannel方法来返回对应的Channel。

   Channel中最常见的三个方法是:map、read和write。其中map将Channel对应的部分或全部数据映射的ByteBuffer,read或write方法有一系列重载的形式用于读取数据。

  eg.将WelcomeServlet.java的内容复制到a.txt中去,并在控制台打印处内容。

public class FileChannelTest
{
    public static void main(String[] args)
    {
        FileChannel inChannel=null;
        FileChannel outChannel=null;
        FileChannel randomChannel=null;
        File f=new File("D://WelcomeServlet.java");
        try
        {
            FileInputStream fs=new FileInputStream(f);
            inChannel=fs.getChannel();
            
            MappedByteBuffer buffer=inChannel.map(FileChannel.MapMode.READ_ONLY,0, f.length());//将inChannel里的全部数据映射成ByteBuffer
            Charset charset=Charset.forName("GBK");
            outChannel=new FileOutputStream("D://a.txt").getChannel();
            
            outChannel.write(buffer);
            buffer.clear();
            
            CharsetDecoder decoder=charset.newDecoder();//创建解码器对象
            CharBuffer charBuffer=decoder.decode(buffer);//使用解码器将ByteBuffer转换为charBuffer
            System.out.println(charBuffer);     //获取对应字符串
        } 
        catch (FileNotFoundException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } 
        catch (IOException e)
        {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }
}

 

 

 

 

 

 

 

 

 

  

  

 

  

posted @ 2015-04-23 18:59  温布利往事  阅读(1102)  评论(0编辑  收藏  举报