IO流之二

一、处理流之一:缓冲流

缓冲是缓冲到内存中。

(1)FileInputStream,FileOutputStream,FileReader,FileWriter是基于硬盘的,比较慢。
缓冲流是基于内存的,可以绕过硬盘的限制,快上好几万倍。

(2)为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组。

(3)根据数据操作单位可以把缓冲流分为:
BufferedInputStreamBufferedOutputStream
BufferedReaderBufferedWriter

(4)缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。

(5)对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush()将会使内存中的数据立刻写出。

输入流操作:

import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test("D:\\test2\\abc\\a\\b\\c\\tt.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test (String path) throws Exception{
        FileInputStream fi = new FileInputStream(path);
        BufferedInputStream br = new BufferedInputStream(fi);
        byte[] b = new byte[10];
        br.read(b);
        br.close();
        fi.close();  //先开的后关
        System.out.println(new String(b));
    }
}

输出流操作:

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test("D:\\test2\\abc\\a\\b\\c\\tt1.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test(String path) throws Exception{
        FileOutputStream fo = new FileOutputStream(path);
        BufferedOutputStream bo = new BufferedOutputStream(fo);

        String s = "vicky";
        bo.write(s.getBytes());
        bo.flush();

        fo.close();
        bo.close();
    }
}

利用缓冲字节流复制文件:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test {
    public static void main(String[] args) {
        Test.copy("D:\\test2\\tt2.txt","D:\\test2\\abc\\a\\tt.txt");
    }

    public static void copy (String from, String to) {
        try {
            FileInputStream fi = new FileInputStream(from);
            FileOutputStream fo = new FileOutputStream(to);
            BufferedInputStream bi = new BufferedInputStream(fi);
            BufferedOutputStream bo = new BufferedOutputStream(fo);

            byte[] b = new byte[10];
            bi.read(b);
            bo.write(b);
            bo.flush();

            bo.close();
            bi.close();
            fo.close();
            fi.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

利用缓冲字符流复制文件:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Test {
    public static void main(String[] args) {
        try {
            Test.copy("D:\\test2\\abc\\a\\tt.txt","D:\\test2\\abc\\a\\b\\tt.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void copy (String from, String to) throws Exception{
        BufferedReader br = new BufferedReader(new FileReader(from));
        BufferedWriter bw = new BufferedWriter(new FileWriter(to));

        char[] ch = new char[10];
        br.read(ch);
        bw.write(ch);
        bw.flush();

        br.close();
        bw.close();
    }
}

字节流和字符流基本操作一样。只是字节流用byte数组来接受流数据,而字符流用char数组来接受流数据。
并且由于字节流是基于二进制的,所以应用范围更广。

Buffered 和 File 基本形象上是一样的,只不过一个基于内存,一个基于硬盘。

二、处理流之二:转换流

编码格式:
所有文件都有编码模式。对于 txt 和 java 文件来说一般有三种编码方式:ISO8859-1、GBK和UTF-8。

第一种叫西欧编码,是纯英文编码,不适用于汉字。

后两种可以用于中文或英文。一般使用UTF-8编码。txt一般默认的是GBK。

转换流

  • 转换流提供了在字节流和字符流之间的转换。
  • Java API提供了两个转换流:InputStreamReader 和 OutputStreamWriter。
  • 字节流中的数据都是字符时,转成字符流操作更高效。

转换字节输入流为字符输入流:

import java.io.FileInputStream;
import java.io.InputStreamReader;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test() throws Exception{
        //字节流转换为字符流

        FileInputStream fi = new FileInputStream("D:\\test2\\tt2.txt");
        InputStreamReader in = new InputStreamReader(fi,"GBK"); //第一个参数是字节流,第二个参数是编码方式
        //注意在转换字符流的时候,设置的字符集编码方式要与读取的文件的编码方式一致,否则会出现乱码


        char[] c = new char[100];
        int len = 0;
        while ((len = in.read(c)) != -1) {
            System.out.println(new String(c,0,len));
        }
        in.close();
        fi.close();
    }
}

转换字节输出流为字符输出流:

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test() throws Exception{
        OutputStreamWriter sw = new OutputStreamWriter(new FileOutputStream("D:\\test2\\tt2.txt"),"GBK");
        String s = "胡hu";
        sw.write(s);
        sw.flush();
        sw.close();
    }
}

三、处理流之三:标准输入输出流

  • System.in 和 System.out 分别代表了系统标准的输入和输出设备。
  • 默认输入设备是键盘,输出设备是显示器。
  • System.in 的类型是 InputStream。
  • System.out 的类型是 PrintStream,而它是OutputStream的子类FilterOutputStream的子类。

需求:把控制台输入的内容写到指定的txt文件中,当接收到字符串“over”时就停止运行。

import java.io.*;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test("D:\\test2\\tt3.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test(String toPath) throws Exception{
        InputStreamReader is = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(is);
        BufferedWriter bw = new BufferedWriter(new FileWriter(toPath));
        String line = "";
        while ((line = br.readLine()) != null) {
            if (line.equals("over"))
                break;
            //读取的每一行都写入txt文件中
            bw.write(line);
        }
        bw.flush();
        bw.close();
        br.close();
        is.close();
    }
}

四、处理流之四:打印流

PrintStream:字节打印流
PrintWriter:字符打印流

五、处理流之五:数据流

专门用来做基本数据类型的读写。

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

public class Test {
    public static void main(String[] args) {
        try {
            Test.test("D:\\test2\\tt4.txt");
            Test.test2("D:\\test2\\tt4.txt");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void test (String path) throws Exception{
        //数据输出流:DataOutputStream
        //用数据输出流写到文件中的基本数据类型的数据是乱码,无法直接辨认,需要数据的输入流来读取
        DataOutputStream out = new DataOutputStream(new FileOutputStream(path));
        out.writeInt(100);
        out.flush();
        out.close();
    }
    public static void test2 (String path) throws Exception {
        DataInputStream in = new DataInputStream(new FileInputStream(path));
        System.out.println(in.readInt());  //用数据输入流读取数据输出流写到文件中的数据时,要保证使用和当时写的数据类型一致的类型来读取
        //比如写的时候用out.writeInt(),那么读的时候就得用in.readInt()
        in.close();
    }
}

六、处理流之六:对象流

对象流主要是为了对象的持久化(存到硬盘)对象的网络传输

用于存储和读取对象的处理流。可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。涉及两个类:ObjectInputStream、ObjectOutputStream。

序列化(Serialize):
用 ObjectOutputStream 类将一个Java对象写入IO流中。

反序列化(Deserilize):
用 ObjectInputStream 类从IO流中回复Java对象。

ObjectOutputStream 类和 ObjectInputStream类不能序列化 static 和 transient 修饰的成员变量。即序列化和反序列化针对的是对象的属性而不适用于类的属性。

对象的序列化

序列化是RMI(Remote Method Invoke,远程方法调用)过程的参数和返回值都必须实现的机制。
RMI是JavaEE的基础。因此序列化机制是JavaEE平台的基础。

如果需要让某个对象支持序列化机制,则必须让其类是可序列化的。而为了让某个类是可序列化的,该类必须实现 SerializableExternalizable 两个接口之一。一般用 Serializable。

凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:private static final long serialVersionUID; 用来表明类的不同版本间的兼容性。

import java.io.*;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test2();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //序列化测试
    public static void test1() throws Exception{
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\test2\\tt5.txt"));
        Person p = new Person();
        p.name = "张三";
        p.age = 18;
        out.writeObject(p);
        out.flush();
        out.close();
    }

    //反序列化测试
    public static void test2() throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\test2\\tt5.txt"));
        Object o = in.readObject();
        Person p = (Person) o;
        in.close();
        System.out.println(p.name);
        System.out.println(p.age);
    }
}

class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int age;
}

注意:对象的序列化与反序列化使用的类要严格一致。包名、类名、类结构等所有内容都要一致。

七、RandomAccessFile类

RandomAccessFile类支持“随机访问”的方式。
随机”是指程序可以直接跳到文件的任意地方来读、写文件。

RandomAccessFile 类对象包含一个记录指针,用以标示当前读写处的位置。
RandomAccessFile 类对象可以自由移动记录指针。
long getFilePointer():获取文件记录指针的当前位置。
void seek(long pos):将文件记录指针定位到 pos 位置。

import java.io.RandomAccessFile;

public class Test {
    public static void main(String[] args) {
        try {
            Test.test2();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //随机读文件
    public static void test1() throws Exception{
        //RandomAccessFile 的构造器有两个参数,参数1是读写文件的路径
        //参数2是指定访问模式
        //r:以只读方式打开
        //rw:打开以便读取和写入
        //rwd:打开以便读取和写入,同步文件内容的更新
        //rws:打开以便读取和写入,同步文件内容和元数据的更新
        RandomAccessFile ra = new RandomAccessFile("D:\\test2\\tt6.txt","r");
        ra.seek(2);  //设置读取文件内容的起始点
        //注意换行符(两个字节)
        //通过设置读取文件内容的起始点,来达到从文件的任意位置读取
        byte[] b = new byte[100];
        int len = 0;
        while ((len = ra.read(b)) != -1) {
            System.out.println(new String(b,0,len));
        }
        ra.close();
    }

    //随机写文件
    public static void test2() throws Exception{
        RandomAccessFile ra = new RandomAccessFile("D:\\test2\\tt7.txt","rw");
        ra.seek(0); //在开头写
        //ra.seek(ra.length()); //在结尾写
        //注意:如果在文件开头或者中间的某个位置开始写的化,就会用写的内容覆盖掉等长度的原内容
        String s = "hello";
        ra.write(s.getBytes());
        ra.close();
    }
}

你可能感兴趣的:(IO流之二)