java的io是实现输入和输出的基础,可以方便的实现数据的输入和输出操作。在java中把不同的输入/输出源(键盘,文件,网络连接等)抽象表述为“流”(stream)。通过流的形式允许java程序使用相同的方式来访问不同的输入/输出源。stram是从起源(source)到接收的(sink)的有序数据。

注:可以理解数据的流动,就是一个数据流。IO流最终要以对象来体现,对象都存在IO包中。

java 常见流 java里的流_java 常见流


字节流

处理字节数据的流对象。设备上的数据无论是图片或者dvd,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据,但是在处理字符上的速度不如字符流。

字符流:
因为字符每个国家都不一样,所以涉及到了字符编码问题,那么GBK编码的中文用unicode编码解析是有问题的,所以需要获取中文字节数据的同时+ 指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。

流的体系因为功能不同,但是有共性内容,不断抽取,形成继承体系。该体系一共有四个基类,而且都是抽象类。
字节流:InputStream OutputStream
字符流:Reader Writer

常见字节流:
InputStream:是表示字节输入流的所有类的超类。
|— FileInputStream:从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。
|— FilterInputStream:包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。
|— BufferedInputStream:该类实现缓冲的输入流。
|— Stream:
|— ObjectInputStream:
|— PipedInputStream:

OutputStream:此抽象类是表示输出字节流的所有类的超类。
|— FileOutputStream:文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。
|— FilterOutputStream:此类是过滤输出流的所有类的超类。
|— BufferedOutputStream:该类实现缓冲的输出流。
|— PrintStream:
|— DataOutputStream:
|— ObjectOutputStream:
|— PipedOutputStream:

常见字符流:
Reader:用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。
|—BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
|—LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
|—InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
|—FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
|—CharArrayReader:
|—StringReader:

Writer:写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。
|—BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
|—OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
|—FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。
|—PrintWriter:
|—CharArrayWriter:
|—StringWriter:

总结常见的几种IO使用场景:

1.flush()和close()的区别:
flush():刷新缓冲区,将缓冲区中的数据刷到目的地文件中。
close(): 关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。

public static void main(String[] args) throws IOException { //读、写都会发生IO异常
    /*
    1:创建一个字符输出流对象,用于操作文件。该对象一建立,就必须明确数据存储位置,是一个文件。
    2:对象产生后,会在堆内存中有一个实体,同时也调用了系统底层资源,在指定的位置创建了一个存储数据的文件。
    3:如果指定位置,出现了同名文件,文件会被覆盖。
    */
    FileWriter fw = new FileWriter("demo.txt"); // FileNotFoundException
    /*
    调用Writer类中的write方法写入字符串。字符串并未直接写入到目的地中,而是写入到了流中,(其实是写入到内存缓冲区中)。怎么把数据弄到文件中?
    */
    fw.write("abcde");
    fw.flush(); // 刷新缓冲区,将缓冲区中的数据刷到目的地文件中。
    fw.close(); // 关闭流,其实关闭的就是java调用的系统底层资源。在关闭前,会先刷新该流。

2.实现文件的拷贝;

----------使用字节流实现文件拷贝

public static void main(String[] args) throws Exception{
        FileInputStream in=null;
        FileOutputStream out=null;
            //新建一个文件目录
            File file=new File("D:\\JSP\\ycc.java");
            //创建新文件,但是目录要自己创建,
            file.createNewFile();
            //构造输入流,从哪里读取数据
            in=new FileInputStream("C:\\WiFi_Log.txt");
            //构造输出流,前面输入流的读取的数据输出到新文件
            out=new FileOutputStream(file);
            //通过逐个读取,存入字节,实现文件拷贝
            int c;
            while((c=in.read())!=-1){
                out.write(c);
            }
            in.close();
            out.close();
    }

------------使用字符流实现文件的拷贝

public static void main(String[] args) throws Exception{
        FileReader in=null;
        FileWriter out=null;

        in=new FileReader("C:\\WiFi_Log.txt");
        out=new FileWriter("D:\\JSP\\ycc-1.java");
        int c;
        while((c=in.read())!=-1){
            out.write(c);
        }
        in.close();
        out.close();
    }

------------------使用缓冲流实现拷贝文件

public static void main(String[] args) throws Exception{
        BufferedReader in=null;
        BufferedWriter out=null;

        in=new BufferedReader(new FileReader("C:\\WiFi_Log.txt"));
        out=new BufferedWriter(new FileWriter("D:\\JSP\\yxx.java"));

        String s;
        //逐行读取,存入字符串,实现文件拷贝
        while((s=in.readLine())!=null){
            out.write(s);
            //写入一个分行符,否则内容在一行显示
            out.newLine();
        }

    }
  • 缓冲流的出现时为了提高流的操作效率而出现的.
  • 需要被提高效率的流作为参数传递给缓冲流的构造函数
  • 在缓冲流中封装了一个数组,存入数据后一次取出

3.对象的序列化
目的:将一个具体的对象进行持久化,写入到硬盘上。
注意:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。

如何将非静态的数据不进行序列化?用transient 关键字修饰此变量即可。

Serializable:用于启动对象的序列化功能,可以强制让指定类具备序列化功能,该接口中没有成员,这是一个标记接口。这个标记接口用于给序列化类提供UID。这个uid是依据类中的成员的数字签名进行运行获取的。如果不需要自动获取一个uid,可以在类中,手动指定一个名称为serialVersionUID id号。依据编译器的不同,或者对信息的高度敏感性。最好每一个序列化的类都进行手动显示的UID的指定。

public class IOTest4 {

    public static void readObj() throws Exception{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\obj.txt"));
        Object obj=ois.readObject();
        System.out.println(obj.toString());
    }

    public static void writeObj() throws Exception{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\obj.txt"));
        oos.writeObject(new Person("zhangsan",25));
        oos.close();
    }

    public static void main(String[] args)throws Exception{
        writeObj();
        readObj();
    }
}
public class Person implements Serializable {
    private static final long serialVersionUID=42L;
    private transient String name;//用transient修饰后name将不会进行序列化
    public int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return name+" ;; "+age;
    }
}