Java IO 流处理

1 流式输入/输出原理

数据以字节或者字符的形式,通过流(节点流/处理流)进行输入输出。

java.io包(阻塞)
java.nio包(非阻塞,jdk5)

2 输入流和输出流

根据数据从程序角度来看,从文件里读数据叫输入流,写文件叫输出流。

一个字节为单位的读写,叫字节流。
一个字符为单位的读写,叫字节流。

注意:

一个字节为8bit,一个字符是2个字节(一个汉字是一个字符,读汉字的时候建议字符流)。

InputStream:字节流,输入流
OutputStream:字节流,输出流

Reader:字符流,输入流
Writer:字符流,输出流

3 节点流和处理流

节点流连接数据源和程序。处理流包裹节点流,提供更强大的流能力。

节点流类型
处理流类型

4 InputStream(输入流)

image.png

InputStream的基本方法

说明:

read()方法是一个字节一个字节地往外读,每读取一个字节,就处理一个字节。read(byte[] buffer)方法读取数据时,先把读取到的数据填满这个byte[]类型的数组buffer(buffer是内存里面的一块缓冲区),然后再处理数组里面的数据。

5 OutputStream(输出流)

image.png

OutputStream的基本方法

6 Reader流

image.png

Reader的基本方法

7 Writer流

image.png

Writer的基本方法

8 节点流的使用

以File类型的节点流说明。

image.png
package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * File类型的节点流
 * 使用FileInputStream流来读取FileInputStream.java文件的内容
 */
public class FileStreamMain {
    public static void main(String[] args) {
        int b = 0; // read() 方法读取字节,并以整数的形式返回,-1表示返回末尾
        // 字节流读中文会乱码
        FileInputStream in = null;
        // 字符流读中英文都可以正确显示,每次读一个字符
//        FileReader in = null;
        try {
            in = new FileInputStream("D:\\1.txt");
//            in = new FileReader("D:/1.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println("系统找不到指定文件!");
            System.exit(-1); // 系统非正常退出
        }
        long num = 0; // 记录读到的字节/字符数
        try {
            while ((b = in.read()) != -1) {
                System.out.println((char)b);
                num++;
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("文件读取错误!");
        } finally {
            try {
                in.close(); // 关闭流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * File类型的节点流
 * 使用FileOutputStream流往一个文件里面写入数据
 */
public class FileOutputStreamMain {
    public static void main(String[] args) {
        int b = 0;
        FileInputStream in = null;
        FileOutputStream out = null;
//        FileReader reader = null;
//        FileWriter writer = null;
        try {
            in = new FileInputStream("D:\\1.txt");
            out = new FileOutputStream("D:/2.txt");
            while ((b = in.read()) != -1) {
                out.write(b);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

package io;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 字符节点流
 *
 */
public class FileReadMain {
    public static void main(String[] args) {
        FileWriter writer = null;
        FileReader reader = null;
        try {
            writer = new FileWriter("D:/3.txt");
            // 把0~60000里面的所有整数都输出
            // 全世界各个国家的文字都0~60000内的整数的形式来表示
            for (int i = 0; i <=6000; i++) {
                writer.write(i); // 以字符的形式写入
            }
            reader = new FileReader("D:\\3.txt");
            int b = 0, num = 0;
            while((b = reader.read())!= -1){
                System.out.print((char)b + "\t");
                num++;
            }
            System.out.println("总共读取了"+num+"个字符");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

9 处理流的使用

缓冲流(Buffering)

带有缓冲区的,缓冲区(Buffer)就是内存里面的一小块区域,读写数据时都是先把数据放到这块缓冲区域里面,减少io对硬盘的访问次数。

package io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 处理流
 * Buffer类型的处理流
 *
 */
public class BufferStreamMain {
    public static void main(String[] args) {
        FileInputStream inputStream = null;
        int c = 0;
        try {
            inputStream = new FileInputStream("D:/1.txt");
            // 在FileInputStream节点流的外面套接一层处理流BufferedInputStream
            BufferedInputStream inputStream1 = new BufferedInputStream(inputStream);
            System.out.println((char) inputStream1.read());
            System.out.println((char) inputStream1.read());
            inputStream1.mark(100); // 在第100个字符处做一个标记
            for (int i = 0; i <= 10 && (c = inputStream1.read()) != -1; i++) {
                System.out.println((char) c);
            }
            inputStream1.reset(); // 重新回到原来标记的地方
            for (int i = 0; i <= 10 && (c = inputStream1.read()) != -1; i++) {
                System.out.println((char) c);
            }
            inputStream1.close();

            BufferedWriter writer = new BufferedWriter(new FileWriter("D:\\1.txt"));
            String s = null;
            for (int i = 0; i < 100; i++) {
                s = String.valueOf(Math.random()); //“Math.random()”将会生成一系列介于0~1之间的随机数
                writer.write(s);
                writer.newLine(); // 调用newLine()方法使得每写入一个随机数就换行显示
            }
            writer.flush(); // 调用flush()方法清空缓冲区

            BufferedReader reader = new BufferedReader(new FileReader("D:/1.txt"));
            while ((s = reader.readLine()) != null) {
                // readLine()方法读取文件中的数据时是一行一行读取的
                // 使用readLine()方法读取数据返回的字符串为空值后则表示已经读取到文件的末尾了
                System.out.println(s);
            }
            writer.close();
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}

转换流

转换流非常的有用,它可以把一个字节流转换成一个字符流,转换流有两种,一种叫InputStreamReader,另一种叫OutputStreamWriter。

InputStream是字节流,Reader是字符流,InputStreamReader就是把InputStream转换成Reader。
OutputStream是字节流,Writer是字符流,OutputStreamWriter就是把OutputStream转换成Writer。

把OutputStream转换成Writer之后就可以一个字符一个字符地通过管道写入数据了,而且还可以写入字符串。我们如果用一个FileOutputStream流往文件里面写东西,得要一个字节一个字节地写进去,但是如果我们在FileOutputStream流上面套上一个字符转换流,那我们就可以一个字符串一个字符串地写进去。

package io;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * 转换流
 * 处理流
 * 字节流--》 字符流
 *
 */
public class InputStreamMain {
    public static void main(String[] args) {
        try {
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("D:/1.txt"));
            writer.write("abafsd");
            System.out.println(writer.getEncoding()); // 使用getEncoding()方法取得当前系统的默认字符编码
            writer.close();
            // 如果在调用FileOutputStream的构造方法时没有加入true,那么新加入的字符串就会替换掉原来写入的字符串,
            // 在调用构造方法时指定了字符的编码
            writer = new OutputStreamWriter(new FileOutputStream("D:/1.txt", true),
                    "ISO8859_1");
            // 再次向指定的文件写入字符串,新写入的字符串加入到原来字符串的后面
            writer.write("1111");
            System.out.println(writer.getEncoding());
            writer.close();

            // System.in这里的in是一个标准的输入流,用来接收从键盘输入的数据
            InputStreamReader reader = new InputStreamReader(System.in);
            BufferedReader reader1 = new BufferedReader(reader);
            String s = null;
            s = reader1.readLine();
            while (s != null) {
                System.out.println(s.toUpperCase());
                s = reader1.readLine(); // 在循环体内继续接收从键盘的输入
                if (s.equalsIgnoreCase("exit")) {
                    break;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

数据流
package io;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * 数据流
 * 处理流
 *
 */
public class DataStreamMain {
    public static void main(String[] args) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        // 在输出流的外面套上一层数据流,用来处理int,double类型的数
        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
        try {
            dataOutputStream.writeDouble(Math.random());
            dataOutputStream.writeBoolean(true);

            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            System.out.println(inputStream.available());
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            // 先写进去的就先读出来,调用readDouble()方法读取出写入的随机数
            System.out.println(dataInputStream.readDouble());
            // 后写进去的就后读出来,这里面的读取顺序不能更改位置,否则会打印出不正确的结果
            System.out.println(dataInputStream.readBoolean());
            dataInputStream.close();
            inputStream.close();
            dataInputStream.close();
            dataOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

打印流——Print
package io;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintStreamMain {
    public static void main(String[] args) {
        PrintStream printStream = null;
        try {
            FileOutputStream outputStream = new FileOutputStream("D:/1.txt");
            printStream = new PrintStream(outputStream); // 在输出流的外面套接一层打印流,用来控制打印输出
            if (printStream != null) {
                // 这里调用setOut()方法改变了输出窗口,以前写System.out.print()默认的输出窗口就是命令行窗口.
                System.setOut(printStream);
                // 但现在使用System.setOut(ps)将打印输出窗口改成了由ps指定的文件里面,
                // 通过这样设置以后,打印输出时都会在指定的文件内打印
            }
            for (char c = 0; c <= 6000; c++) {
                System.out.println(c + "\t");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

image.png
对象流——Object
package io;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 对象流
 * 处理流
 *
 */
public class ObjectStreamMain {
    public static void main(String[] args) {
        T t = new T();
        t.k = 101;
        try {
            FileOutputStream outputStream = new FileOutputStream("D:/1.txt");
            // ObjectOutputStream流专门用来处理Object的,
            // 在fos流的外面套接ObjectOutputStream流就可以直接把一个Object写进去
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(t); // 直接把一个t对象写入到指定的文件里面
            objectOutputStream.flush();
            objectOutputStream.close();

            FileInputStream inputStream = new FileInputStream("D:/1.txt");
            // ObjectInputStream专门用来读一个Object的
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            T t1 = (T) objectInputStream.readObject();
            System.out.println(t1.k);
            objectInputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }



}

// 凡是要将一个类的对象序列化成一个字节流就必须实现Serializable接口
// Serializable接口中没有定义方法,Serializable接口是一个标记性接口,用来给类作标记,只是起到一个标记作用。
// 这个标记是给编译器看的,编译器看到这个标记之后就可以知道这个类可以被序列化 如果想把某个类的对象序列化,就必须得实现Serializable接口
class T implements Serializable {
    int i = 10;
    int j = 9;
    transient  int k = 100;
    // 在声明变量时如果加上transient关键字,那么这个变量就会被当作是透明的,即不存在。
}

直接实现Serializable接口的类是JDK自动把这个类的对象序列化,而如果实现public interface Externalizable extends Serializable的类则可以自己控制对象的序列化,建议能让JDK自己控制序列化的就不要让自己去控制。

10 IO流总结

IO流总结
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342