高级Java工程师必备 ----- 深刻分析 Java IO (三)

概述

Java IO即Java 输入输出系统。无论咱们编写何种应用,都不免和各类输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,好比咱们要考虑和哪一种媒介进行IO(文件、控制台、网络),咱们还要考虑具体和它们的通讯方式(顺序、随机、二进制、按字符、按字、按行等等)。Java类库的设计者经过设计大量的类来攻克这些难题,这些类就位于java.io包中。html

在JDK1.4以后,为了提升Java IO的效率,Java又提供了一套新的IO,Java New IO简称Java NIO。它在标准java代码中提供了高速的面向块的IO操做。本篇文章重点介绍Java IO,关于Java NIO请参考个人另两篇文章: java

高级Java工程师必备 ----- 深刻分析 Java IO (一)BIO网络

高级Java工程师必备 ----- 深刻分析 Java IO (二)NIO框架

Java IO类库的框架

首先看个图:dom

 Java IO的类型

虽然java IO类库庞大,但整体来讲其框架仍是很清楚的。从是读媒介仍是写媒介的维度看,Java IO能够分为:性能

  1. 输入流:InputStream和Reader
  2. 输出流:OutputStream和Writer

而从其处理流的类型的维度上看,Java IO又能够分为:spa

  1. 字节流:InputStream和OutputStream
  2. 字符流:Reader和Writer

下面这幅图就清晰的描述了JavaIO的分类:设计

- 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

咱们的程序须要经过InputStream或Reader从数据源读取数据,而后用OutputStream或者Writer将数据写入到目标媒介中。其中,InputStream和Reader与数据源相关联,OutputStream和writer与目标媒介相关联。指针

Java IO的基本用法

Java IO :字节流

经过上面的介绍咱们已经知道,字节流对应的类应该是InputStream和OutputStream,而在咱们实际开发中,咱们应该根据不一样的媒介类型选用相应的子类来处理。下面咱们就用字节流来操做文件媒介:code

例1,用字节流写文件

public static void writeByteToFile() throws IOException{ String hello= new String( "hello word!"); byte[] byteArray= hello.getBytes(); File file= new File( "d:/test.txt"); //由于是用字节流来写媒介,因此对应的是OutputStream //又由于媒介对象是文件,因此用到子类是FileOutputStream
    OutputStream os= new FileOutputStream( file); os.write( byteArray); os.close(); }

例2,用字节流读文件

public static void readByteFromFile() throws IOException{ File file= new File( "d:/test.txt"); byte[] byteArray= new byte[( int) file.length()]; //由于是用字节流来读媒介,因此对应的是InputStream //又由于媒介对象是文件,因此用到子类是FileInputStream
    InputStream is= new FileInputStream( file); int size= is.read( byteArray); System. out.println( "大小:"+size +";内容:" +new String(byteArray)); is.close(); }

CopyFileDemo

package com.chenhao.io.byteIO; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @author ChenHao * */
public class CopyFileDemo { /** * @param args * @throws FileNotFoundException */
    public static void main(String[] args) { String src ="E:/xp/test"; String dest="e:/xp/test/4.jpg"; try { copyFile(src,dest); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("文件不存在"); } catch (IOException e) { e.printStackTrace(); System.out.println("拷贝文件失败|关闭流失败"); } } /** * 文件的拷贝 * @param 源文件路径 * @param 目录文件路径 * @throws FileNotFoundException,IOException * @return 
     */
    public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException { //一、创建联系 源(存在且为文件) +目的地(文件能够不存在) 
        File src =new File(srcPath); File dest =new File(destPath); if(! src.isFile()){ //不是文件或者为null
            System.out.println("只能拷贝文件"); throw new IOException("只能拷贝文件"); } //二、选择流
        InputStream is =new FileInputStream(src); OutputStream os =new FileOutputStream(dest); //三、文件拷贝 循环+读取+写出
        byte[] flush =new byte[1024]; int len =0; //读取
        while(-1!=(len=is.read(flush))){ //写出
            os.write(flush, 0, len); } os.flush(); //强制刷出 //关闭流
 os.close(); is.close(); } }

Java IO :字符流

一样,字符流对应的类应该是Reader和Writer。下面咱们就用字符流来操做文件媒介:

例3,用字符流读文件

public static void writeCharToFile() throws IOException{ String hello= new String( "hello word!"); File file= new File( "d:/test.txt"); //由于是用字符流来读媒介,因此对应的是Writer,又由于媒介对象是文件,因此用到子类是FileWriter
    Writer os= new FileWriter( file); os.write( hello); os.close(); }

例4,用字符流写文件

public static void readCharFromFile() throws IOException{ File file= new File( "d:/test.txt"); //由于是用字符流来读媒介,因此对应的是Reader //又由于媒介对象是文件,因此用到子类是FileReader
    Reader reader= new FileReader( file); char [] byteArray= new char[( int) file.length()]; int size= reader.read( byteArray); System. out.println( "大小:"+size +";内容:" +new String(byteArray)); reader.close(); }

Java IO :字节流转换为字符流

字节流能够转换成字符流,java.io包中提供的InputStreamReader类就能够实现,固然从其命名上就能够看出它的做用。其实这涉及到另外一个概念,IO流的组合,后面咱们详细介绍。下面看一个简单的例子:

例5 ,字节流转换为字符流

public static void convertByteToChar() throws IOException{ File file= new File( "d:/test.txt"); //得到一个字节流
    InputStream is= new FileInputStream( file); //把字节流转换为字符流,其实就是把字符流和字节流组合的结果。
    Reader reader= new InputStreamReader( is); char [] byteArray= new char[( int) file.length()]; int size= reader.read( byteArray); System. out.println( "大小:"+size +";内容:" +new String(byteArray)); is.close(); reader.close(); }

Java IO:文件媒介操做

例6 ,File操做

public class FileDemo { public static void main(String[] args) { //检查文件是否存在
        File file = new File( "d:/test.txt"); boolean fileExists = file.exists(); System. out.println( fileExists); //建立文件目录,若父目录不存在则返回false
        File file2 = new File( "d:/fatherDir/subDir"); boolean dirCreated = file2.mkdir(); System. out.println( dirCreated); //建立文件目录,若父目录不存则连同父目录一块儿建立
        File file3 = new File( "d:/fatherDir/subDir2"); boolean dirCreated2 = file3.mkdirs(); System. out.println( dirCreated2); File file4= new File( "d:/test.txt"); //判断长度
         long length = file4.length(); //重命名文件
         boolean isRenamed = file4.renameTo( new File("d:/test2.txt")); //删除文件
         boolean isDeleted = file4.delete(); File file5= new File( "d:/fatherDir/subDir"); //是不是目录
         boolean isDirectory = file5.isDirectory(); //列出文件名
        String[] fileNames = file5.list(); //列出目录
        File[]   files = file4.listFiles(); } }

随机读取File文件

经过上面的例子咱们已经知道,咱们能够用FileInputStream(文件字符流)或FileReader(文件字节流)来读文件,这两个类可让咱们分别以字符和字节的方式来读取文件内容,可是它们都有一个不足之处,就是只能从文件头开始读,而后读到文件结束。

可是有时候咱们只但愿读取文件的一部分,或者是说随机的读取文件,那么咱们就能够利用RandomAccessFile。RandomAccessFile提供了seek()方法,用来定位将要读写文件的指针位置,咱们也能够经过调用getFilePointer()方法来获取当前指针的位置,具体看下面的例子:

例7,随机读取文件

public static void randomAccessFileRead() throws IOException { // 建立一个RandomAccessFile对象
    RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw"); // 经过seek方法来移动读写位置的指针
     file.seek(10); // 获取当前指针
     long pointerBegin = file.getFilePointer(); // 从当前指针开始读
     byte[] contents = new byte[1024]; file.read( contents); long pointerEnd = file.getFilePointer(); System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" + new String(contents)); file.close(); }

例8,随机写入文件

public static void randomAccessFileWrite() throws IOException { // 建立一个RandomAccessFile对象
     RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw"); // 经过seek方法来移动读写位置的指针
     file.seek(10); // 获取当前指针
     long pointerBegin = file.getFilePointer(); // 从当前指针位置开始写
     file.write( "HELLO WORD".getBytes()); long pointerEnd = file.getFilePointer(); System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" ); file.close(); }

Java IO:BufferedInputStream和BufferedOutputStream

BufferedInputStream顾名思义,就是在对流进行写入时提供一个buffer来提升IO效率。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操做的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操做效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候,能提高IO性能。

使用BufferedInputStream十分简单,只要把普通的输入流和BufferedInputStream组合到一块儿便可。咱们把上面的例2改形成用BufferedInputStream进行读文件,请看下面例子:

例10 ,用缓冲流读文件

public static void readByBufferedInputStream() throws IOException { File file = new File( "d:/test.txt"); byte[] byteArray = new byte[( int) file.length()]; //能够在构造参数中传入buffer大小
     InputStream is = new BufferedInputStream( new FileInputStream(file),2*1024); int size = is.read( byteArray); System. out.println( "大小:" + size + ";内容:" + new String(byteArray)); is.close(); }

BufferedOutputStream的状况和BufferedInputStream一致,在这里就很少作描述了。

copyFile

package com.chenhao.io.buffered; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * 字节流文件拷贝+缓冲流 ,提升性能 * 缓冲流(节点流) * @author ChenHao * */
public class BufferedByteDemo { public static void main(String[] args) { String src ="E:/xp/test"; String dest="e:/xp/test/4.jpg"; try { copyFile(src,dest); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("文件不存在"); } catch (IOException e) { e.printStackTrace(); System.out.println("拷贝文件失败|关闭流失败"); } } /** * 文件的拷贝 * @param 源文件路径 * @param 目录文件路径 * @throws FileNotFoundException,IOException * @return 
     */
    public static void copyFile(String srcPath,String destPath) throws FileNotFoundException,IOException { //一、创建联系 源(存在且为文件) +目的地(文件能够不存在) 
        File src =new File(srcPath); File dest =new File(destPath); if(! src.isFile()){ //不是文件或者为null
            System.out.println("只能拷贝文件"); throw new IOException("只能拷贝文件"); } //二、选择流
        InputStream is =new BufferedInputStream(new FileInputStream(src)); OutputStream os =new BufferedOutputStream( new FileOutputStream(dest)); //三、文件拷贝 循环+读取+写出
        byte[] flush =new byte[1024]; int len =0; //读取
        while(-1!=(len=is.read(flush))){ //写出
            os.write(flush, 0, len); } os.flush(); //强制刷出 //关闭流
 os.close(); is.close(); } }

Java IO:BufferedReader和BufferedWriter

BufferedReader、BufferedWriter 的做用基本和BufferedInputStream、BufferedOutputStream一致,具体用法和原理都差很少 ,只不过一个是面向字符流一个是面向字节流。一样,咱们将改造字符流中的例4,给其加上buffer功能,看例子:

public static void readByBufferedReader() throws IOException { File file = new File( "d:/test.txt"); // 在字符流基础上用buffer流包装,也能够指定buffer的大小
     Reader reader = new BufferedReader( new FileReader(file),2*1024); char[] byteArray = new char[( int) file.length()]; int size = reader.read( byteArray); System. out.println( "大小:" + size + ";内容:" + new String(byteArray)); reader.close(); }

另外,BufferedReader提供一个readLine()能够方便地读取一行,而FileInputStream和FileReader只能读取一个字节或者一个字符,所以BufferedReader也被称为行读取器.

public static void keyIn() throws IOException { try (//InputStreamReader是从byte转成char的桥梁
      InputStreamReader reader = new InputStreamReader(System.in); //BufferedReader(Reader in)是char类型输入的包装类
      BufferedReader br = new BufferedReader(reader);) { String line = null; while ((line = br.readLine()) != null) { if (line.equals("exit")) { //System.exit(1);
                 break; } System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } }

Java IO: 序列化与ObjectInputStream、ObjectOutputStream

Serializable

若是你但愿类可以序列化和反序列化,必须实现Serializable接口,就像所展现的ObjectInputStream和ObjectOutputStream例子同样。

ObjectInputStream

ObjectInputStream可以让你从输入流中读取Java对象,而不须要每次读取一个字节。你能够把InputStream包装到ObjectInputStream中,而后就能够从中读取对象了。代码以下:

ObjectInputStream input = new ObjectInputStream(new FileInputStream("object.data")); MyClass object = (MyClass) input.readObject(); //etc.
input.close();

在这个例子中,你读取的对象必须是MyClass的一个实例,而且必须事先经过ObjectOutputStream序列化到“object.data”文件中。

在你序列化和反序列化一个对象以前,该对象的类必须实现了java.io.Serializable接口。

ObjectOutputStream

ObjectOutputStream可以让你把对象写入到输出流中,而不须要每次写入一个字节。你能够把OutputStream包装到ObjectOutputStream中,而后就能够把对象写入到该输出流中了。代码以下:

ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("object.data")); MyClass object = new MyClass();  output.writeObject(object); //etc.
output.close();

例子中序列化的对象object如今能够从ObjectInputStream中读取了。

一样,在你序列化和反序列化一个对象以前,该对象的类必须实现了java.io.Serializable接口。

 

原文出处:https://www.cnblogs.com/java-chen-hao/p/11083740.html

相关文章
相关标签/搜索