Java IO

  一、概述

Java中的IO流是用来处理设备间的数据传输,对于数据的输出输入操作都是用“流”的方式进行的,Java.io 包主要涉及文件,网络数据流,内存缓冲等的输入输出。

按照不同的分类方式,可以把流分为不同的类型。常用的分类有三种:

  • 按照流的方向:输入流(inputStream)和输出流(outputStream)
  • 按照实现功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。)
  • 按照处理数据的单位: 字节流和字符流。Java提供了两种类型的输入输出流:一种是面向字节的流,数据的处理以字节为基本单位;另一种是面向字符的流,用于字符数据的处理,字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java Io流的40多个类都是从如下4个抽象类基类中派生出来的。

InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

二、字节流

(一)FileInputStream

字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流。

public class MyClass {
public class FileIO {
    public  static void main(String[] args)throws IOException {
        FileInputStream file=null;
        try {
            //创建字节输入流
            file=new FileInputStream("D:\\Files\\Java\\Test.txt");
            byte[] b=new byte[1024];
            //用于保存的实际字节数
            int hasRead=0;
            while((hasRead=file.read(b))>0){
                //取出字节,将字节数组转换成字符串进行输出
                System.out.print(new String(b,0,hasRead));
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            file.close();
        }
    }
}

  

(二)FileOutputStream

用来创建一个文件并向文件中写数据。如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。

有两个构造方法可以用来创建 FileOutputStream 对象。

public class FileOutputStreamTest {
    public  static void main(String[] args)throws IOException {
        FileInputStream fis=null;
        FileOutputStream fos=null;
        try {
            //创建字节输入流
            fis=new FileInputStream("D:\\Files\\Java\\Test.txt");
            //创建字节输出流
            fos=new FileOutputStream("D:\\Files\\Java\\newTest.txt");

            byte[] b=new byte[1024];
            int hasRead=0;

            //循环从输入流中取出数据
            while((hasRead=fis.read(b))>0){
                //每读取一次,即写入文件输入流,读了多少,就写多少。
                fos.write(b,0,hasRead);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            fis.close();
            fos.close();
        }
    }
}

  

三、字符流

(一)InputStreamReader

字节流转字符流,它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

public class InputStreamReaderTest {
    public static void main(String[] args) throws IOException {
        // 创建字符输入流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\Files\\Java\\Test.txt"));

        // public int read():一次读取一个字符
//		int ch;
//		while((ch = isr.read()) != -1){
//			System.out.print((char)ch);
//		}

        // public int read(char[] cbuf):一次读取一个字符数组
        char[] chs = new char[1024];
        int len;// 每次真实读到数据的个数
        while((len = isr.read(chs)) != -1){
            System.out.print(new String(chs,0,len));
        }

        isr.close();

    }
}

(二)OutputStreamWriter

 将字符流转换为字节流。是字符流通向字节流的桥梁

public class OutputStreamWriterTest {
    public static void main(String[] args) {


        try {

            // create a new OutputStreamWriter
            OutputStream os = new FileOutputStream("D:\\Files\\Java\\test1.txt");
            OutputStreamWriter writer = new OutputStreamWriter(os);

            // create a new FileInputStream to read what we write
            FileInputStream in = new FileInputStream("D:\\Files\\Java\\test1.txt");

            // write something in the file
            writer.write(70);
            writer.write(71);
            writer.write(72);

            // flush the stream
            writer.flush();

            // read what we write
            for (int i = 0; i < 3; i++) {
                System.out.print("" + (char) in.read());
            }


        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

四、序列化

序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序 列 化 的 实 现 : 将 需 要 被 序 列 化 的 类 实 现 Serializable 接 口 , 该 接 口 没 有 需 要 实 现 的 方 法 , implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 writeObject(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

public class TestWriteObject {
    public static void main(String[] args) {
        String filePath = "D://Files//Java//obj.txt";
        ObjectOutputStream objOutput = null;
        Course c1 = new Course("C language", 3);
        Course c2 = new Course("OS", 4);
        Student s1 = new Student("king", 25);
        s1.setCourse(c1);
        Student s2 = new Student("jason", 23);
        s2.setCourse(c2);
        try {
            objOutput = new ObjectOutputStream(new FileOutputStream(filePath));
            objOutput.writeObject(s1);
            objOutput.writeObject(s2);
            objOutput.writeInt(123);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                objOutput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Info:对象被写入"+filePath);
    }

}

  

public class TestReadObject {
    public static void main(String[] args) {

        String filePath = "D://Files//Java//obj.txt";
        ObjectInputStream objInput = null;
        Student s1 = null,s2 = null;
        int intVal = 0;

        try {
            objInput = new ObjectInputStream(new FileInputStream(filePath));
            s1 = (Student)objInput.readObject();
            s2 = (Student)objInput.readObject();
            intVal = objInput.readInt();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }catch(ClassNotFoundException cnfe){
            cnfe.printStackTrace();
        }finally{

            try {
                objInput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Info:文件"+filePath+"中读取对象");
        System.out.println(s1);
        System.out.println(s1.getCourse());
        System.out.println(s2);
        System.out.println(s2.getCourse());
        System.out.println(intVal);
    }

}
当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被默认序列化的话,则可以使用transient关键字进行声明。如果用transient声明一个实例变量,当对象存储时,它的值不需要维持,而会保持默认值。也就是说,用transient关键字标记的成员变量不参与JVM的默认序列化过程。
例如:ArrayList 中存储数据的数组 elementData 是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。
 
posted @ 2021-03-20 23:46  zq231  阅读(28)  评论(0)    收藏  举报