IO流详细总结

一、IO流简介:
流的定义:流是指一连串流动的字符,是以先进先出方式发送信息的通道。
按流向分:输出流:OutputStream和Writer为基类
                输入流:InputStream和Reader为基类
按处理数据单元划分:字节流:字节输入流:InputStream基类
                                                字节输出流:OutputStream基类
                                  字符流:字符输入流:Reader基类
                                   字节输出流:Writer基类
(字节流是 8 位通用字节流,字符流是16位Unicode字符流)

1.1 InputStream
引入相关的类: InputStream ins =null;
构建输入流,例如FileInputStream:
ins =new FileInputStream(new File(path));
操控字节输入流的,所用的方法也是针对字节的。
常用方法:

返回值类型  
方法名
方法简介
abstract int read( ) 从此输入流中读取下一个字节(此方法是抽象方法,子类必须实现该方法。
int read(byte [ ] b ) 从输入流中读取一定数量的字节,存储在参数指定的字节数组中。
int read(byte [ ] b ,int off ,int len ) 读到 len字节从输入流读入字节数组数据。
long skip( long n ) 跳过并丢弃 n字节从输入流中的数据。
int available( ) 返回此输入流下一个方法可以读取的字节数。
void close( ) 关闭流。

案例:
使用缓冲数组的方法读取文件内容,提高效率

public static void readArr() {
                         // 1、明确源数据源
                        File f = new File("F:/1/余文佳/1.txt");
                         // 2、构建流的对象
                        InputStream ins = null;
                        try {
                                    ins = new FileInputStream(f);
                                     // 3、声明缓冲数组
                                    int i; // 表示读取了多少个字符到数组中
                                    byte[] bt = new byte[5]; // 字节缓冲数组
                                     // 4、读取数据到数组中
                                    //可以读多少写多少,转化成char类型,但是文件中都是英文,如果有中文则输出乱码
                                    while ((i = (ins.read(bt))) != -1) {
                                                for (int j = 0; j < i; j++) {
                                                            System.out.print((char) bt[j]);
                                                }
                                    }
                        } catch (Exception e) {
                                    e.printStackTrace();
                        } finally {
                              //关闭流
                                    try {
                                                if (ins != null) {
                                                            ins.close();
                                                }
                                    } catch (Exception e) {
                                                e.printStackTrace();
                                    }
                        }
            }

tips:
关于InputStream.read(byte[] b)和InputStream.read(byte[] b,int off,int len)这两个方法都是用来从流里读取多个字节的,有经验的程序员就会发现,这两个方法经常 读取不到自己想要读取的个数的字节。比如第一个方法,程序员往往希望程序能读取到b.length个字节,而实际情况是,系统往往读取不了这么多。仔细阅读Java的API说明就发现了,这个方法 并不保证能读取这么多个字节,它只能保证最多读取这么多个字节(最少1个)。因此,如果要让程序读取count个字节,最好用以下代码:

byte[] b = new byte[count];
int readCount = 0; // 已经成功读取的字节的个数
while (readCount < count) {
readCount += in.read(bytes, readCount, count - readCount);
}

用这段代码可以保证读取count个字节,除非中途遇到IO异常或者到了数据流的结尾(EOFException)

1.2 OutputStream
常用方法:

返回值类型
方法名
方法简介
void flush( ) 刷新输出流,是缓存数据被写出来
void write(byte [ ] b) 写b.length 字节从指定的字节数组的输出流
void write(byte [ ] b, int off, int len) 写len字节从字节数组数据中到输入流
abstract int write( int b ) 将指定的字节写入该输出流中
void close( ) 关闭流

1.1.1  FileInputStream

    FileInputStream是读取原始字节的图像数据流。读取字符流,考虑使用FileReader。
常用方法:
见InputStream中的方法

构建输入流:(准备工作)

FIle file =new File(path);
InputStream ins =null;
ins =new FileInputStream; //这里需要try catch

读取文件字符:

int i =0;
while( ( i=ins.read( ) ) != -1){
           System.out.println( i );
  }  //输出的是自动转化的ASCII值,此处会抛出  IOException,需要try catch

或者提高效率,使用缓冲数组byte[ ] b,可读取英文文件,需要转化成char字符:

int len =0;
byte [ ]b=new byte [ 1024 ];//建立缓冲流数组
while((len=ins.read( b ))!= -1){
         for( int j=0;j<len ;j++){
         System.out.println( (char) bt [ j ] );
     }
} //中间嵌套for循环,读多少输出多少,中文不可用,会输出乱码-->此处会抛出  IOException,需要try catch

完整案例

package cn.pojo;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo {
            public static void main(String[] args) {
                        readByte();
                        readArr();
            }
            /**
             * 读取字节
             */
            public static void readByte() {
                         // 1、明确源数据源
                        File f = new File("F:\\1\\余文佳\\1.txt");
                         // 2、构建输入流对象
                        InputStream ins = null;
                        try {
                                    ins = new FileInputStream(f);
                                    int i;
                                     // 3、 读取文件字符
                                    while ((i = ins.read()) != -1) {
                                                System.out.println("i=" + i); // 输出为转化的ascii码值
                                    }
                        } catch (Exception e) {
                                    e.printStackTrace();
                        } finally {
                                     // 4、关闭资源
                                    if (ins != null) {
                                                try {
                                                            ins.close();
                                                } catch (Exception e) {
                                                            e.printStackTrace();
                                                }
                                    }
                        }
            }
            // 2、使用缓冲数组的方法读取文件内容,提高效率
            public static void readArr() {
                         // 1、明确源数据源
                         File f = new File("F:/1/余文佳/1.txt");
                         // 2、构建流的对象
                        InputStream ins = null;
                        try {
                                    ins = new FileInputStream(f);
                                     // 3、声明缓冲数组
                                    int i; // 表示读取了多少个字符到数组中
                                    byte[] bt = new byte[5]; // 字节缓冲数组
                                     // 4、读取数据到数组中
                                    while ((i = (ins.read(bt))) != -1) {
                                                for (int j = 0; j < i; j++) {
                                                            System.out.print((char) bt[j]);
                                                }
                                    }
                        } catch (Exception e) {
                                    e.printStackTrace();
                        } finally {
                                     //关闭流
                                    try {
                                                if (ins != null) {
                                                            ins.close();
                                                }
                                    } catch (Exception e) {
                                                e.printStackTrace();
                                    }
                        }
            }
}


1.2.1  FileOutputStream

是OutputSTream的子类,主要功能是从源文件写入资料至指定文件中

构造方法1、FileOutputStream( File file ) // 创建“File对象”对应的“文件输入流”;默认“追加模式”是false,
                                         即“写到输出的流内容”不是以追加的方式添加到文件中。若要追加则为(File file, true);
                   2、FileOutputStream( String path ) / / 创建 “文件(路径为path)”对应的“文件输入流”;  (若没有,自动系统调用方法创建)
                                                                                 默认“追加模式”是false,即“写到输出的流内容”不是以追加的方式添加到文件中。 若要追加则为(String path, true);  

try {
                // 构造方法1
                File file = new File("E:/java47.txt");
                FileOutputStream fos1 = new FileOutputStream(file);
                // File file = new File("E:/java47.txt");
                // FileOutputStream fos1 = new  FileOutputStream(file);
                // 没有该文件会直接创建文件,但不能有多级目录,否则会报错,或者这只是个目录
                // -->java.io.FileNotFoundException:E:\java\java48.txt (系统找不到指定的路径。)
                // 构造方法2       
                FileOutputStream fos2 = new FileOutputStream("E:/java/java48.txt");// 规则如上
           } catch (Exception e) {
                e.printStackTrace();
           }


常用方法:(同OutputStream)
返回值类型
方法名
方法简介
void flush( ) 刷新输出流,是缓存数据被写出来
void write(byte [ ] b) 写b.length 字节从指定的字节数组的输出流
void write(byte [ ] b, int off, int len) 写len字节从字节数组数据中到输入流
abstract int write( int b ) 将指定的字节写入该输出流中
void close( ) 关闭流
应用主要步骤 :1、构建字节输出流对象
                           2、写数据
                           3、关闭流
案例:

package cn.pojo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

/**
* 字节输出流案例
*
* @author kuang
*
*/
public final class OutputStreamDemo {

        public static void main(String[] args) {
                // 1、明确目标数据源
                File f = new File("E:/java48/java48.txt");
                // 判断文件是否存在,否则创建
                if (!f.exists()) {
                    f.getParentFile().mkdirs();// 先创建目录
                    try {
                        f.createNewFile();// 再创建文件 此处需要处理异常,
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                // 2、构建输出流对象(通过子类实例化父类的对象)
                OutputStream outs = null ; // 首先准备好一个输出的对象
                try {
                    outs = new FileOutputStream(f) ; // 构造方法 ,实例化,此处需要处理异常
                    // 执行写入文件的操作
                    String st = "java48班" ; // 创建字符串
                    byte[] bt = st.getBytes(); // 只能输出byte数组,所以将字符串变为byte数组
                                                           // 使用String st.getByte();方法
                    outs.write(bt); // 将内容输出,保存文件
                    outs.flush(); // 刷新输出流
                    System.out.println("写入成功!"); // 若(文件夹必须存在)没有文件,会创建文件然后写入;若文件已有相同内容,则直接覆盖
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                        // 4、关闭资源
                        if (outs != null) { 
                        try {
                            outs.close(); // 此处也要处理异常
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
        }
}

Test FileInputStream  FileOutputStream  实现文件的复制

package cn.pojo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class Demo {
     // 检查文件是否存在,否则创建
     public static void checkFile(File file) {
           if (!file.exists()) {
                file.getParentFile().mkdirs();// 创建多级目录
                try {
                     file.createNewFile();// 创建文件,此处需要处理异常
                     System.out.println("创建文件成功!");
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
     public static void main(String[] args) {
           // 明确源文件和目标文件
           File o = new File("E:/java48/java48.txt");// 源文件
           File t = new File("E:/java48/新建.txt");// 目标文件
           checkFile(t);// 这里仅仅检查了目标文件
           // 构建输入、输出流对象
           InputStream ins = null; // 输入的对象
           OutputStream outs = null; // 输出的对象
           // 进行实例化,需要处理异常
           try {
                ins = new FileInputStream(o);// 源文件作为输入对象--->若要拼接后面加上true
                outs = new FileOutputStream(t);// 目标文件作为输出对象--->若要拼接后面加上true
                // 创建缓冲数组
                byte[] b = new byte[1024];
                int len = 0;
                // 执行边读边写操作
                while ((len = ins.read(b)) != -1) {
                     outs.write(b, 0, len);
                }
                // 刷新输出流
                outs.flush();
                // 至此复制成功
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                // 关闭流(先开的后关)
                try {
                     if (outs != null) {// 为了避免空指针异常,进行判空
                           outs.close();
                     }
                     if (ins != null) {
                           ins.close();
                     }
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
}


1.1.2  BufferedInputStream

带缓冲区的输入流,默认缓冲区大小是8M,能够减少访问磁盘的次数,提高文件读取性能;
是 FileInputStream 的子类。 实现了装饰设计模式!
BufferedInputStream没有无参构造方法,它必须传入一个InputStream(一般是FileInputStream),来一起使用,以提高读写效率。
构造方法1、BufferInputStream(InputStream in)// 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
                                                                                       创建一个内部缓冲区数组并将其存储在 buf 中,该buf的大小默认为8192。
                   2、BufferedInputStream(InputStream in, int size) //创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
                                                                                                    创建一个长度为 size 的内部缓冲区数组并将其存储在 buf 中。
常用方法
返回值类型
方法名
方法简介
abstract int read( ) 从此输入流中读取下一个字节(此方法是抽象方法,子类必须实现该方法。
int read(byte [ ] b ) 从输入流中读取一定数量的字节,存储在参数指定的字节数组中。
int read(byte [ ] b ,int off ,int len ) 读到 len字节从输入流读入字节数组数据。




1.2.2   BufferedOutputStream

带缓冲区的输出流,能够提高文件的写入效率。 实现了装饰设计模式!

BufferedOutputStream没有无参构造方法,它必须传入一个OutputStream(一般是FileOutputStream),来一起使用,以提高读写效率。
构造方法 1、BufferOutputStream(OutputStream outs) // 创建一个 BufferedInputStream 并保存其参数,即输出流outs,将数据写入指定的基本输入流中。
                                                                                                     
                   2、BufferedOutputStream(OutputStream outs, int size) //创建具有指定缓冲区大小的 BufferedOutputStream ,即输出流outs, 将数据写入指定的基本输入流中
                                                                                               
常用方法
返回值类型
方法名
方法简介
void flush( ) 刷新输出流,是缓存数据被写出来
void write(byte [ ] b) 写b.length 字节从指定的字节数组的输出流
void write(byte [ ] b, int off, int len) 写len字节从字节数组数据中到输入流
Test 使用  BufferedInputStream  和  BufferedOutputStream  实现文件的复制
(与上面的FileInputStream Test类似)

tips:为什么要用BufferedInputStream 和 BufferedOutputStream?
优点:效率高 
缺点:内存占用多
why?
        不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。
带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多。


1.1.3  DataInputStream
        数据 输入流 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。 DataInputStream 对于  多线程 访问不一定是安全的。  线程安全 是可选的,它由此类方法的使用者负责。

构造方法: DataInputStream(InputStream in); 

常用方法:

返回值类型
方法名
方法简介
int read(byte [ ]  b) 读取一定数量的字节从包含输入流并存入缓冲区阵列b
int read (byte [ ]  b, int off, int len) 读到 len 从包含输入流读入字节数组数据字节
boolean readBoolean( ) 读 true / false
byte readByte( ) 读取并返回一个输入字节
char readChar( ) 读取两个字节返回一个 char 价值
float readFloat( ) 四字节读取输入并返回一个 float 价值
double readDouble( ) 八字节读取输入并返回一个 double 价值
int readInt( ) 四字节读取输入并返回一个 int 价值
String readLine( ) 从输入流读取下一行文本
short readShort( ) 两字节读取输入并返回一个 short 价值
String readUTF( ) 读取一个字符串,一直采用 modified UTF-8 编码格式

1.2.3  DataOutputStream

        数据 输入流 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。 DataInputStream 对于多线程访问不一定是安全的。  线程安全 是可选的,它由此类方法的使用者负责。

构造方法:  DataOutputStream( OutputStream outs);

常用方法:


返回值类型
方法名
方法简介
void flush( ) 刷新数据输出流
int size( ) 返回柜台 written 电流值,这个数据写入输出流的字节数为止
void write( int b ) 将指定的字节(论证b的低八位)的底层输出流
void write( byte [ ] b, int off, int len ) 写 len 字节指定字节数组中的起始偏移量 off 当前输出流
void writeBoolean( boolean v ) 写一个 boolean 当前输出流作为一个字节的值
void writeByte( int v ) 写了 byte 当前输出流作为一个字节的值
void writeBytes( String s ) 将字符串写入到基础的输出流作为字节序列
void writeChar( int v ) 写一个char当前输出流作为一个双字节的值,高字节优先
void writeChars( String s ) 将字符串写入底层输出流,作为一个字符序列
void writeFloat( float v ) 将浮点型参数的 int使用 floatToIntBits方法在类 Float,然后写道, int值基本为4字节输出流量,高字节优先。
void writeDouble( double v ) 将双参数到一个 long使用 doubleToLongBits方法在类 Double,然后写道, long值基本的输出流的字节的数量,高字节优先。
void writeInt( int v ) 写一个 int当前输出流为四个字节,高字节优先。
void writeShort( int v ) 写一个 short当前输出流的两个字节,高字节优先。
void writeUTF( String str ) 一个字符串写入到输出流的潜在使用在一个机器无关的方式 modified UTF-8编码。
案例 1:


package cn.pojo;

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

//二进制流
public class Demo2 {

    public static void main (String[] args ) {
         // 1、指明目标和源
          File o = new File("temp/Hello.class");
         File t = new File( "tmp/Hello.class" );
         // 2、构建流对象
         DataInputStream dis = null;
          DataOutputStream dos = null;
        try {
            dis = new DataInputStream( new FileInputStream( o ));
             dos = new DataOutputStream( new FileOutputStream( t ));
            int i;
             // 3、读写流
            while (( i = dis .read()) != -1) {
                dos .write(i);
            }
             dos .flush();
             System. out .println( "操作成功!" );
         } catch (Exception e ) {
            e .printStackTrace();
        } finally {
             // 4、关闭流
            try {
                if ( dos != null ) {
                    dos .close();
                }
                if ( dis != null ) {
                    dis .close();
                 }
            } catch (Exception e ) {
                e .printStackTrace();
            }
        }
    }
}


案例 2:
package cn.pojo;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo {
     // 检查文件是否存在,否则创建
     public static void checkFile(File file) {
           if (!file.exists()) {
                file.getParentFile().mkdirs();// 创建多级目录
                try {
                     file.createNewFile();// 创建文件,此处需要处理异常
                     System.out.println("创建文件成功!");
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
     // 明确源文件和目标文件
     public static void main(String[] args) throws IOException {
           myWrite();
           myReader();
     }
     private static void myWrite() throws IOException {
           // TODO Auto-generated method stub
           // 创建数据输出流对象
           File o = new File("E:/java48/111.txt");// 源文件
           File t = new File("E:/java48/新建111.txt");// 目标文件
           checkFile(o);
           checkFile(t);
           FileOutputStream fos = new FileOutputStream(o);
           DataOutputStream dos = new DataOutputStream(fos);
           // 写数据
           dos.writeByte(10);
           dos.writeShort(100);
           dos.writeInt(1000);
           dos.writeLong(10000);
           dos.writeFloat(12.34F);
           dos.writeDouble(12.56);
           dos.writeChar('a');
           dos.writeBoolean(true);
           // 释放资源
           dos.close();
     }
     private static void myReader() throws IOException {
           // TODO Auto-generated method stub
           // 创建数据输入流对象
           File o = new File("E:/java48/111.txt");// 源文件
           FileInputStream fis = new FileInputStream(o);
           DataInputStream dis = new DataInputStream(fis);
           // 读数据
           byte b = dis.readByte();
           short s = dis.readShort();
           int i = dis.readInt();
           long l = dis.readLong();
           float f = dis.readFloat();
           double d = dis.readDouble();
           char c = dis.readChar();
           boolean bl = dis.readBoolean();
           // 释放资源
           dis.close();
           System.out.println(b);
           System.out.println(s);
           System.out.println(i);
           System.out.println(l);
           System.out.println(f);
           System.out.println(d);
           System.out.println(c);
           System.out.println(bl);
     }
}

输出内容为:
10
100
1000
10000
12.34
12.56
a
true


1.1.4  ObjectInputStream :对象输入流

特点 : 可以从输入流中读取java对象,而不需要每次读取一个字节,需要把InputStream包装到ObjectInputStream中,就可以从中读取对象,对象必须实现序列化,对象类实现Serializable接口
例:(实现序列化)
public class Pet implements Serializable {
      private static final long serialVersionUID = 1L;
 }

构造方法: 1、ObjectInputStream( ) ;
                 2、ObjectInputStream( InputStream ins) ; 
                         
例如:创建方式 1 :
             String path = "xx";// 路径和文件
           File file = new File(path);// 创建文件
           // 构建InputStream,然后ObjectInputStream
           InputStream ins = null;
           ObjectInputStream ois = null;
           try {
                ins = new FileInputStream(file);// 这里需要处理异常
                ois = new ObjectInputStream(ins);// 两层构造
           } catch (Exception e) {
                e.printStackTrace();
           }
创建方式2:
                    String path = "xx";// 路径和文件
           try {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));// 多层构造,需要处理异常
           } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
           }


常用方法:

返回值类型
方法名
方法简介
void close( ) 关闭输入流
int read( ) 读取一个字节的数据
int read( byte [ ] b, int off, int len )  读入一个字节数组
boolean readBoolean( ) 在布尔值中读取
byte readByte( ) 读取一个8位字节
char readChar( ) 读取一个16位字符
double readDouble( )  
float readFloat( )  
int readInt( ) 读取一个32位的int
String readLine( )   过时的
Object readObject( ) 读取对象输入流中的对象
String readUTF( ) 读modified UTF-8的格式字符串


1.2.4  ObjectOutputStream :对象输出流

特点: 能够让你把对象写入到输出流中,而不需要每次写入一个字节。你可以把OutputStream包装到ObjectOutputStream中,然后就可以把对象写入到该输出流中了
           对象必须实现序列化,对象类 实现Serializable接口
例:(实现序列化)
public class Pet implements Serializable {
      private static final long serialVersionUID = 1L;
 }

构造方法:    1、ObjectOutputStream( ) ;
                        2、ObjectOutputStream( OutputStream ins) ; 

例如:创建方式 1 :
         String path = "xx";// 路径和文件
        File file = new File(path);// 创建文件
        // 构建OutputStream,然后ObjectOutputStream
        OutputStream outs = null;
        ObjectOutputStream oos = null;
        try {
           outs = new FileOutputStream(file);// 这里需要处理异常
           oos = new ObjectOutputStream(outs);// 两层构造:先用FileOutputSTream,再用ObjectOutputStream
        } catch (Exception e) {
             e.printStackTrace();
        }
创建 方式 2:
        String path = "xx";// 路径和文件
        try {
             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));// 多层构造,需要处理异常
        } catch (Exception e) {
             e.printStackTrace();
        }

常用方法:

返回值类型
方法名
方法简介
void close( ) 关闭流
void flush( ) 刷新流
protect Object replaceObject( ) 这种方法将允许受信任的子类对象来代替一个物体对另一个序列化期间
void write( byte [ ] b ) 写入一个字节数组
void write( byte [ ] b, int off, int len ) 写入字节数组的字节数
void write( int val ) 写一个字节
void writeBoolean( boolean val ) 写一个布尔值
void writeByte( byte val ) 写入一个8位字节
void writeChar( int val ) 写入一个16位字符
void writeInt( int val ) 写入一个32位长的int
void writeObject( Object obj ) 写入指定对象的对象
void writeUTF( String str ) 原始数据写在 modified UTF-8格式字符串
ObjiectInputStream 和 ObjectOutputStream 案例:(创建一个宠物类,放入一个集合中,使用者两个类进行读写操作)

package cn.pojo;
import java.io.Serializable;
//宠物类
public class Pet implements Serializable {// 要实现序列化
     private static final long serialVersionUID = 514910705505845579L;
     private String id;// id编号
     private String name;// 昵称
     public Pet() {
     }
     public Pet(String id, String name) {
           this.id = id;
           this.name = name;
     }
     public String getId() {
           return id;
     }
     public void setId(String id) {
           this.id = id;
     }
     public String getName() {
           return name;
     }
     public void setName(String name) {
           this.name = name;
     }
     @Override
     public String toString() {
           return "Pet [id=" + id + ", name=" + name + "]";
     }
}


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
public class Demo3_Pet {
     public static void main(String[] args) {
           // 1、明确当前目标和源
           File o = new File("F:/temp/pet.txt");
           File t = new File("F:/temp/pet.txt");
           ArrayList<Pet> arr = new ArrayList<Pet>();
           Pet pet1 = new Pet("001", "小白");
           Pet pet2 = new Pet("002", "小绿");
           Pet pet3 = new Pet("003", "大黄");
           arr.add(pet1);
           arr.add(pet2);
           arr.add(pet3);
           // 2、构建流对象
           InputStream ins = null;
           OutputStream outs = null;
           ObjectInputStream ois = null;
           ObjectOutputStream oos = null;
           try {
                outs = new FileOutputStream(o);
                oos = new ObjectOutputStream(outs);
                // 输出对象信息:序列化
                oos.writeObject(arr);
                oos.flush();
                System.out.println("写出成功!");
                // 读文件对象:反序列化
                ins = new FileInputStream(o);
                ois = new ObjectInputStream(ins);
                Object ob = ois.readObject();
                // 遍历输出集合中对象信息
                if (ob instanceof ArrayList) {
                     @SuppressWarnings("unchecked")
                     ArrayList<Pet> li = (ArrayList<Pet>) ob;
                     for (Pet p : li) {
                           System.out.println(p);
                     }
                }
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                // 关闭流------>这里与其他不同,先关闭InputStream的,再关闭OutputStream,(仅本总结中)
                try {
                     if (ins != null) {
                           ins.close();
                     }
                     if (outs != null) {
                           outs.close();
                     }
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
}

Tips:
        该对象首先要可序列化,然后把多个对象存储到容器里,如ArrayList<?> list;  
        然后把list序列化存储,然后再反序列化读文件,读出来就是一串对象了


字符流:

1、 字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串。字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的。字符流操作的是缓冲区(当我们对文件进行读写操作时如果不调用close() 或 flush()方法时不能看到数据的变化)。
2、字符输入流 Reader 基类
     字符输出流 Writer 基类
3、Reader 和 Writer都是抽象类


2.1.1  InputStreamReader

特点:将字节输入流转换为字符输入流。是字节流通向字符流的桥梁,可以指定字节流转换为字符流的字符集。

构造方法:1、InputStreamReader( InputStream ins) ; 创建一个默认字符集的 InputStreamReader
                    2、InputStreamReader( InputStream ins  ,“ encoding” ) ; 创建使用指定字符集的 InputStreamReader


常用方法:
返回值类型
方法名
方法简介
void close( ) 关闭流
String getEncoding( ) 返回此流使用的字符编码名称
int read( ) 读取单个字符
int read( char [ ] ch, int off, int len ) 将字符读入一个数组的一部分
boolean ready( ) 告诉是否该流已准备好阅读
读文件内容的常用三种方法:1、int  read()

         //public int read() throws IOException
         //读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
         public static void readOneStr ( ) throws IOException{
             InputStreamReader isr= new InputStreamReader( new FileInputStream( "E:\\test\\javaIo\\1.txt" ));
             int ch=0;
             while ((ch=isr.read())!=-1){
                 System.out.print(( char )ch);
             }
             isr.close();
        }

2、int  read( char [ ]ch, int off, in len )

         //public int read(char[] cbuf ) throws IOException
         //将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
         public static void readOneStrArr() throws IOException {
             InputStreamReader isr = new InputStreamReader ( new FileInputStream( "E:\\test\\javaIo\\1.txt" ));
             char [] ch = new char [1024];
             int len =0;
             while (( len = isr .read( ch ))!=-1){
                 System. out .print( new String( ch ,0, len ));
             }
             isr .close();
         }

3、int read( char [ ] ch)

        //public int read(char[] cbuf ) throws IOException
         //将字符读入数组的某一部分。在某个输入可用、发生 I/O 错误或者到达流的末尾前,此方法一直阻塞。
         public static void readOneStrArrLen( ) throws IOException{
             InputStreamReader isr= new InputStreamReader( new FileInputStream( "E:\\test\\javaIo\\1.txt" ));
             char [] ch= new char [1024];
             int len=0;
             while ((len=isr.read(ch,0,ch.length))!=-1){
                 System.out.print( new String(ch,0,len));
             }
             isr.close();
         }


2.2.1  OutputStreamWriter  

特点: 将字节输出流转为字符输出流,是字符流通向字节流的桥梁,可使用指定的 encoding 要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,
          否则将接受平台默认的字符集。

构造方法:1、OutputStreamWriter(OutputStream outs) ; 创建使用默认字符编码的 OutputStreamWriter
                 2、 OutputStreamWriter(OutputStream outs , “ecoding”) ;  可以设置编码格式

常用方法:

返回值类型
方法名
方法简介
void close( ) 关闭流
void flush( ) 刷新流
String getEcoding( ) 返回此流使用的字符编码格式名称
void writer( int val ) 写入一个字符
void writer( char [ ]ch, int off, int len ) 写入一个字符数组的一部分
void writer( String str, int off, int len ) 写入字符串的一部分
用OutputStreamWriter 将内存中的数据写入文件中有5种方式:

1、 void   writer( int  val )

  //public void write(int c)throws IOException
 //写入单个字符。要写入的字符包含在给定整数值的 16 个低位中,16 高位被忽略。
         public static void writerOneChar() throws IOException{
             OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
             osw.write(97);//char ch=(char)97; 
             osw.write('c');
             osw.flush();
             osw.close();
         }

2、 void    writer( char [ ]ch )

  //public void write(char[] cbuf)throws IOException 写入字符数组。
         public static void writerCharArr() throws IOException{
             OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
             char [] ch=new char[]{'我','爱','中','国'};
             osw.write(ch);
             osw.flush();
             osw.close();
         }

3、 void    writer( char [ ]ch, int off, int len)

 //public abstract void write(char[] cbuf,int off,int len)throws IOException 写入字符数组的某一部分。
         public static void writerCharArrLen() throws IOException{
             OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
             char [] ch=new char[]{'我','爱','中','国'};
             osw.write(ch,0,ch.length-1);
             osw.flush();
             osw.close();
         }

4、 viod   writer( String str )

  //public void write(String str) throws IOException  写入字符串。
         public static void writerOneStr() throws IOException{
             OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
             osw.write("中国");
             osw.flush();
             osw.close();
         }

5、 void   writer( String str, int off ,int len )

 //public void write(String str,int off, int len)throws IOException; 写入字符串的某一部分。
         public static void writerOneStrArrLen() throws IOException{
             OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("E:\\test\\javaIo\\1.txt"));
             String str="我爱中国";
             osw.write(str,0,str.length()-2);
             osw.flush();
             osw.close();
         }


包装流设置字符集的案例,使用InputStreamReader 和 OUtputStreamWriter:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Scanner;
/**
 * 包装流设置字符集
 *
 * @author kuang
 *
 */
public class homework_2 {
     public static void main(String[] args) {
           // 确定源和目标文件
           Scanner sc = new Scanner(System.in);
           File o = new File("kh/java48.template");
           File t = new File("kh/java48.txt");
           check(o);
           check(t);
           // 构建流对象
           InputStream ins = null;
           OutputStream outs = null;
           InputStreamReader insr = null;
           OutputStreamWriter outsw = null;
           try {
                outs = new FileOutputStream(o);// 先做为目标文件写入内容
                outsw = new OutputStreamWriter(outs, "UTF-8");//编码格式为UTF-8
                System.out.println("输入你要写入的内容:");
                String msg = sc.next();
                // 写入内容
                outsw.write(msg);
                // 刷新
                outsw.flush();
                System.out.println("已经完全写入!");
                ins = new FileInputStream(o);// 作为源文件
                insr = new InputStreamReader(ins, "UTF-8");//编码格式为UTF-8
                outs = new FileOutputStream(t);// 作为写入的目标文件
                outsw = new OutputStreamWriter(outs, "UTF-8");//编码格式为UTF-8
                char[] ch = new char[1024];
                int i = 0;
                // 执行边读边写
                while ((i = insr.read(ch)) != -1) {
                     outsw.write(ch, 0, i);
                }
                // 刷新
                outsw.flush();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                // 关闭流
                try {
                     if (outs != null) {
                           outs.close();
                     }
                     if (ins != null) {
                           ins.close();
                     }
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
     public static void check(File file) {
           try {
                if (!file.exists()) {
                     file.getParentFile().mkdirs();// 创建文件夹
                     file.createNewFile();// 创建文件
                     System.out.println("没有该文件!已创建成功!");
                }
           } catch (Exception e) {
                e.printStackTrace();
           }
     }
}

2.1.1.1  FileReader 
2.2.1.1  FileWriter 
与上面InputStreamReader 和 OutputStreamWriter没啥区别 ,不多说

2.1.2  BufferedReader(缓冲流)

特点: 字节输入缓冲流,从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine

构造方法: 1、BufferedReader( Reader in ) ; 创建一个使用默认大小输入缓冲区的缓冲字符输入流
                 2、BufferedReader( Reader in, int sz ) ; 创建一个使用指定大小的输入缓冲区的缓冲字符输入流

常用方法:
该类读取文本的方法就是父类Reader提供的read()系列方法(见2.1.1 InputStreamReader)。在这里仅介绍他自己特有的方法readLine()  

返回值类型
方法名
方法简介
String readLine( ) 读一行文本 --> 特有
例:

//public String readLine()throws IOException读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行。
         public static void readLineTest() throws IOException{
             BufferedReader br=new BufferedReader(new FileReader("E:\\test\\javaIo\\1.txt"));               
             String str=null;
             while((str=br.readLine())!=null){
                 System.out.println(str);
             }
             br.close();
         }


2.2.2  BufferedWriter (缓冲流)

特点:字节输出缓冲流,将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。 该类提供了 newLine() 方法,它使用平台自己的行分隔符概念,此概念由系统属性 line.separator 定义。

构造方法: 1、BufferedWriter( Writer out ) ;创建一个使用默认大小输出缓冲区的缓冲字符输出流
                 2、BufferedWriter( Writer out,  int sz ) ;创建一个新的缓冲字符输出流,该流使用给定大小的输出缓冲区。

常用方法:
该类写入文本的方法就是父类Writer提供的write()系列方法(见2.2.1 OutputStreamWriter),在这里仅介绍他特有的newLine( )方法。

返回值类型
方法名
方法简介
void newLine( ) 写行分隔符
例:

  public static void newLineTest() throws IOException{
                   BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\test\\javaIo\\2.txt"));
                   bw.write("爱我");
                   bw.newLine();
                   bw.write("中华");
                   bw.flush();
                   bw.close();
               }
           //结果:(加入了换行符)
             爱我
             中华

字符缓冲流 案例:(使用 BufferedReader 和 BufferedWriter)

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.io.Writer;
/**
 * 字符缓冲流
 *
 * @author kuang
 *
 */
public class Demo2 {
     public static void main(String[] args) {
           // 1、指明源和目标
           File o = new File("F:/temp/java48.template");
           File t = new File("F:/temp/java48.txt");
           // 2、构建流的对象
           Reader re = null;
           Writer wt = null;
           BufferedReader bfr = null;
           BufferedWriter bfw = null;
           try {
                re = new FileReader(o);
                bfr = new BufferedReader(re);
                wt = new FileWriter(t);
                bfw = new BufferedWriter(wt);
                String msg = null;
                // 读取操作
                while ((msg = bfr.readLine()) != null) {// 读一行
                     // System.out.println(msg);
                     bfw.write(msg);
                     bfw.write("\r\n");// 执行换行,读一行 写一行 换行
                     // 或者 :bfw.newLine();//换行
                }
                bfw.flush();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                // 关闭流
                try {
                     if (wt != null) {// 为了避免空指针异常,进行判空
                           wt.close();
                     }
                     if (re != null) {
                           re.close();
                     }
                } catch (Exception e) {
                     e.printStackTrace();
                }
           }
     }
}

         (= =!)






猜你喜欢

转载自blog.csdn.net/kk_bluebule/article/details/79157404