IO:Input / Output
完成输入 / 输出
应用程序运行时——数据在内存中 ←→ 把数据写入硬盘(磁带)
内存中的数据不可持久保存
输入:从外部存储器(硬盘、磁带、U盘)把数据读入内存中。
输出:从内存中把数据写入外部存储器(硬盘、磁带、U盘)中,这样就可以保证,即使程序退出了,数据依然不会丢失。
listRoot:列出磁盘上所有的根目录
exists:判断是否存在
mkdir:创建目录
listFiles():列出当前目录下所有的文件和子目录
listFiles(FileFilter filter):列出当前目录下符合指定条件的文件和子目录
listFiles(FilenameFilter filter)
- import java.io.File;
-
- public class ListE {
-
- public static void main(String[] args) {
- // 创建一个File,它代表了E盘
- File e = new File("e:/Program Files");
-
- List(e);
- }
-
- public static void List(File dir) {
- System.out.println(dir + "目录下包含的文件和子目录有:");
- // 该方法返回当前目录所包含的所有文件和子目录
- File[] files = dir.listFiles();
-
- for (File file : files) {
- System.out.println(" " + file);
- // 如果file是目录,继续列出该目录下所有文件
- if (file.isDirectory()) {
- List(file);
- }
- }
- }
- }
- import java.io.*;
-
- public class FileFilterTest {
-
- public static void main(String[] args) {
- File e = new File("e:/");
-
- // 返回当前目录所包含的所有*.txt文件,此时就需要对文件进行过滤
- File[] files = e.listFiles(new FileFilter() {
- // pathname就代表正在处理的文件,如果该方法返回true,意味着该文件就被保留,否则该方法将会被过滤掉
- @Override
- // 没有比IOExcepiton更小的,所以只能用try catch
- public boolean accept(File pathname) {
- // 说明文件名以.txt结尾
- try {
- if (pathname.getCanonicalPath().endsWith("txt")) {
- return true;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return false;
- }
- });
-
- for (File file : files) {
- System.out.println(file);
- }
- }
- }
File的特征:只能访问磁盘上的文件和目录,它无法访问文件内容。
如果要访问文件的内容,必须使用IO流。
把外部输入读入当前程序所在内存
把当前程序所在内存的数据输出到外部
处理数据单位是字节(8bit),适应性广、功能强大
处理的数据单元是字符。通常来说它主要用于处理文本文件
在处理文本文件时,比字节流方便
直接和一个IO的物理节点(磁盘上的文件、网络)关联
以节点为基础,包装之后得到的流
都继承了FilterXxx等基类
输入流中的数据单元放入应用程序;应用程序中的数据单元放入输出流。
外部存储器的速度比内存的速度慢,外部存储器的读写与内存的读写并不同步
——通过缓冲就可以解决这种不同步
反正你把流用完了,
- 别忘记调用flush方法(把缓冲中的内容刷入实际的节点)
调用close()也可——系统会在关闭之前,自动刷缓冲
字节流 | 字符流 | ||||
节点流 | InputStream | OutputStream | Reader | Writer | 抽象 |
FileInputStream | FileOutputStream | FileReader | FileWriter | 访问文件 | |
ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter | 数组 | |
PipedInputStream | PipedOutputStream | PipedReader | PipedWriter | 访问管道 | |
StringReader | StringWriter | 访问字符串 | |||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter | 缓冲 |
FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | 抽象 | |
PrintStream | PrintWriter | 打印 | |||
InputStreamReader | OutputStreamWriter | 转换 | |||
DataInputStream | DataOutputStream | 特殊 |
所有以InputStream结尾的都是字节输入流
所有以OutputStream结尾的都是字节输出流
所有以Reader结尾的都是字符输入流
所有以Writer结尾的都是字符输出流
- import java.io.*;
- public class FileInputStreamTest {
- public static void main(String[] args) throws IOException {
- // 创建输入流,相当于得到一根有水的水管
- FileInputStream fis = new FileInputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\FileInputStreamTest.java");
-
- // System.out.print((char)fis.read());// 该方法每次只读一个字节
-
- /*
- * 为了把fis中水滴全部“取出”内存,有两个做法:
- * 1、用大桶
- * 2、用循环
- */
- byte[] buff = new byte[64]; // 我的水桶可以装64个“水滴”
- int hasRead = -1;
- //hasRead = fis.read(buff);// 用“桶”从fis(水管)中取水
- while((hasRead = fis.read(buff)) > 0) {
- // 上一次读取了几个字节,此处就输出几个字节
- System.out.println(new String(buff, 0 ,hasRead));
- }
- }
- }
运行结果:
- import java.io.FileOutputStream;
- import java.io.IOException;
-
- public class FileOutputStreamTest {
- public static void main(String[] args) {
- FileOutputStream fos = null;
- try {
- // 得到输出流,相当于得到一个没有水滴的水管
- fos = new FileOutputStream("abc.txt");
- fos.write(97); // 每次输出"一个字节“
- fos.write(98);
- fos.write(99);
- fos.write(100);
- fos.write(101);
-
- fos.write("自由、民主的普世价值观~".getBytes());
- } catch (IOException ex) {
- ex.printStackTrace();
- } finally {
- try {
- fos.close();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
运行结果:
- import java.io.*;
- public class CopyTest {
- public static void main(String[] args) {
- // JDK 7提供了自动关闭资源的try语句
- try (
- // 创建输入流,得到一个有水滴的水管
- FileInputStream fis = new FileInputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\CopyTest.java");
- // 创建输出流,得到一个空水管
- FileOutputStream fos = new FileOutputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\test.txt");
- )
- {
- int hasRead = -1;
- byte[] buff = new byte[128];
-
- // 从fis里读取水滴,放入buff中
- while((hasRead = fis.read(buff)) > 0) {
- // 将buff中水滴写入fos,hasRead用于控制:读了多少,就写多少
- fos.write(buff, 0, hasRead);
- }
-
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- }
运行结果:
节点流直接与IO节点关联
——IO节点有很多:键盘、网络、文件、磁带……
过滤流的好处:
——消除底层节点之间的差异
——使用过滤流的方法执行IO更加便捷
FileOutputStream →PrintStream
FileWriter→PrintWriter
如果已经知道要读的内容是字符内容,就可按如下方式转换:
InputStream→InputStreamReader→BufferedReader
- import java.io.*;
-
- public class PrintStreamTest {
- public static void main(String[] args) {
- try (
- // 创建节点流,节点流使用不方便
- FileOutputStream fos = new FileOutputStream("D:\\Program Files\\eclipse-java-2023-06-R-win32-x86_64\\workplace\\day\\src\\day13\\my.txt");
- // 把节点流包装成过滤流:消除节点流的差异,而且PrintStream的方法更加方便
- PrintStream ps = new PrintStream(fos);
- )
- {
- ps.println("我想");
- ps.println("我想早");
- ps.println("我想早点");
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
运行结果:
它们是两个特殊的流——它们是过滤流(建立在已有IO的基础之上)
——它们只要增加一些特定的方法来读取特定的数据。
- import java.io.*;
- public class DataOutputStreamTest {
- public static void main(String[] args) {
- try (
- // 创建节点流——与磁盘上的文件关联
- FileOutputStream fos = new FileOutputStream("price.txt");
-
- // 创建过滤流,过滤流建立在节点流的基础上
- DataOutputStream dos = new DataOutputStream(fos);
- )
- {
- dos.writeDouble(3.4);
- dos.writeDouble(5.23);
- dos.writeDouble(4.34);
- dos.writeDouble(5.12);
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
运行结果:
- import java.io.*;
- public class DataInputStreamTest {
- public static void main(String[] args) {
- try (
- // 先创建节点流,与指定物理节点(文件)建立读写
- FileInputStream fis = new FileInputStream("price.txt");
-
- // 以节点流来创建过滤流
- DataInputStream dis = new DataInputStream(fis);
- )
- {
- System.out.println(dis.readDouble());
- System.out.println(dis.readDouble());
- System.out.println(dis.readDouble());
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
运行结果:
System.in——标准输入。通常代表键盘。
System.out——标准输出。通常代表屏幕。
System.setOut() ——可以将标准输出重定向另一个输出流。
- import java.io.*;
- public class SetOutTest {
- public static void main(String[] args) throws Exception{
- // 可以将标准输出重定向到指定的输出流
- System.setOut(new PrintStream("out.txt"));
-
- System.out.println("ABC");
- System.out.println("ABC");
- System.out.println("ABC");
- System.out.println("ABC");
- }
- }
运行结果:输出的内容重定向到out.txt文本文件中
System.setIn() ——可以将标准输出重定向另一个输入流。
- import java.io.*;
- public class RedirectKeyIn {
- public static void main(String[] args) throws Exception {
- // 将标准输入重定向到RedirectKeyIn.java
- System.setIn(new FileInputStream("RedirectKeyIn.java"));
-
- //System.in,它是一个节点流,一般关联着物理键盘
- //直接用System.In(InputStream——节点、字节、输入流)可以读取键盘输入
- //缺点是:太繁琐、而且效率相当低下
- //System.out.println(System.in.read());
-
- InputStreamReader reader = new InputStreamReader(System.in);
-
- BufferedReader br = new BufferedReader(reader);
-
- String line = null;
- // 控制BufferedReader每次读取一行
- while ((line = br.readLine()) != null) {
- System.out.println(line);
- }
- }
- }
运行结果:
该方法的返回值是一个Process对象
Process——代表一个进程。
进程就是运行中的应用程序。
- import java.io.*;
- public class ReadFromProcess {
- public static void main(String[] args) throws Exception{
-
- Runtime runtime = Runtime.getRuntime();
-
- // 启动javac应用程序,返回该应用程序对应的进程
- // Process proc = runtime.exec("javac.exe -encoding UTF8 -d . ReadFromProcess.java");
- Process proc = runtime.exec("javac.exe -encoding UTF8 -d . ReadFromProcess");
-
- // 要得到javac应用程序输出的内容,此处应该用输入流?还是输出流?
- // 对于javac来说,是输出;但对于我们应用程序来说,用输入流
- InputStreamReader reader = new InputStreamReader(proc.getErrorStream());
- BufferedReader br = new BufferedReader(reader);
-
- String line = null;
-
- StringBuilder sb = new StringBuilder();
-
- // 控制BufferedReader每次读取一行
- while ((line = br.readLine()) != null) {
- //System.out.println(line);
- sb.append(line);
- }
-
- // 如果有错误输出
- if (sb.toString().length() > 0) {
- System.out.println("编译出错,错误信息如下----");
- // 输出错误提示
- System.out.println(sb);
- } else {
- System.out.println("成功完成----");
- }
- }
- }
上面为“编译出错”的代码,下面为“成功完成”的代码
Random——想访问文件的哪个点,就访问文件的哪个点(任意)
RandomAccessFile实现了Closeable接口,所以可以使用自动关闭资源的try语句。
1、既可读、又可写、还可追加。相当于InputStream与OutputStream合体。
RandomAccessFile它不会覆盖原有的文件内容。
2、只能访问文件!这就是它的局限性。
- import java.io.*;
- public class RandomAccessFileTest {
- public static void main(String[] args) {
- try (
- // 使用RadomAccessFile创建一个只读的输入流
- RandomAccessFile raf = new RandomAccessFile("RandomAccessFileTest.java", "r");
- )
- {
- byte[] buff = new byte[1024];
- int hasRead = -1;
- while ((hasRead = raf.read(buff)) > 0) {
- System.out.println(new String(buff, 0, hasRead));
- }
-
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
创建RandomAccessFile,需要指定读(r)、写(rw)模式
seek(long pos)——用于把记录指针移动到任意位置,想访问哪个点就访问哪个点。
一开始,它的记录指针位于文件的开始位置。
1、把记录指针移动到最后
2、执行输出即可
- import java.io.RandomAccessFile;
-
- public class AppendTest {
- public static void main(String[] args) {
- try (
- // 使用RadomAccessFile创建一个只读的输入流
- RandomAccessFile raf = new RandomAccessFile("AppendTest.java", "rw");
- )
- {
- // 把记录指针移动到文件的最后
- raf.seek(raf.length());
- raf.write("//做人好累".getBytes());
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
1、把记录指针移动到指定位置
2、从当前位置到文件结尾的内容,先读取,并保存
3、输出要插入的内容
Java对象(内存)->二进制流
1、在有些时候,需要把对象存储到外部存储器中持久化保存。
2、在有些时候,需要把对象通过网络传输。
1、Serializable:接口只是一个标记性的接口,实现该接口无需实现任何方法
2、Externalizable:实现该接口要实现方法。
ObjectInputStream——负责从二进制流“恢复”对象。readObject
ObjectOutputStream——负责把对象保存到二进制流中。writeObject
- import java.io.*;
- class Apple implements Serializable{
- private String name;
- private String color;
- private double weight;
-
- public Apple() {
- super();
- }
-
- public Apple(String name, String color, double weight) {
- super();
- this.name = name;
- this.color = color;
- this.weight = weight;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getColor() {
- return color;
- }
-
- public void setColor(String color) {
- this.color = color;
- }
-
- public double getWeight() {
- return weight;
- }
-
- public void setWeight(double weight) {
- this.weight = weight;
- }
-
- public String toString() {
- return "Apple[name="
- + name +",color=" + color
- + ",weight=" + weight + "]";
- }
- }
-
- public class WriteObject {
- public static void main(String[] args) {
- Apple ap = new Apple("红富士", "红色", 3.4);
- System.out.println(ap);
-
- // 当程序结束时,虚拟机退出,内存中的Apple对象就被销毁了
- try (
- ObjectOutputStream oos = new ObjectOutputStream(
- new FileOutputStream("app.bin"));
- )
- {
- oos.writeObject(ap); //把ap对象写入app.bin文件中
- }
- catch (Exception ex) {
- // TODO: handle exception
- }
- }
- }
- import java.io.*;
- public class ReadObject {
- public static void main(String[] args) {
- try (
- ObjectInputStream ois = new ObjectInputStream(
- new FileInputStream("app.bin"));
- )
- {
- Apple ap = (Apple)ois.readObject();
- System.out.println(ap);
- }
- catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }
字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 | |
访问文件 | InputStream | OutputStream | Reader | Writer |
访问数组 | FileXxx | |||
访问管道 | ByteArrayXxx | CharArrayXxx | ||
访问字符串 | StringXxx | |||
过滤流 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | PrintStream | PrintWriter | ||
转换流 | InputStreamReader | OutputStreamWriter | ||
特殊流 | DataInputStream | DataOutputStream | ||
ObjectInputStream | ObjectOutputStream |
1、它只能访问文件。相当于DataInputStream和DataOutputStream组合
2、任意,由seek(int pos)。