学习图灵基础课以及王争专栏总结
一、File类
File是io操作磁盘文件以及文件目录的一个核心类。虽然名字是文件,但是本质是文件/目录。
在最初学习io时,我老以为io就是操作文件或者目录的。但是后面发现这只是其中的一个类别,io可以是文件,网络,内存,管道,标准输入输出等。
1)常用方法
| 方法名 | 描述 |
| createNewFile() | 创建一个文件 |
| mkdir() | 创建一个目录,只能创建一级 |
| mkdirs() | 创建一个多级目录,如 aaa/bbb/ccc, 同时创建 |
| isFile() | 判断是否是文件 |
| isDirectory() | 判断是否是目录 |
| delete() | 删除文件或空目录 |
| exists() | 是否存在 |
| getName() | 获得文件名字,只有名称,没有路径 |
| getPath() | 获得路径,也会有名称 |
| getAbsolutePath() | 获得绝对路径 |
| getParent() | 获得父类File的名称 |
| getParentFile() | 获得父类File |
| list() | 获得目录下所有文件/目录的名称(只获得该目录下级,不会有下下级) |
| listFiles() | 获得目录下所有文件/目录。 |
| length() | 获得文件的长度。 |
| separator() | 路径的隔开符 |
2)FileFilter接口/FilenameFilter接口:

File.list() 与FilenameFilter配合 ,File.listFiles()可以配合FileFilter/FilenameFilter接口使用。
重写FileFilter里的public boolean accept(File pathname)方法。
用法如下:
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.isDirectory() || pathname.getName().endsWith("txt")){
return true;
}
return false;
}
});
FilenameFilter类似

二、各系统的路径问题
引用自:java 路径中 /与\\ linux系统的路径_linux服务器上java后台项目的上传文件路径是/还是\\-优快云博客
1)windows下的路径
在windows下路径一般为:D:\\demo\\text.txt
2)Linux下的路径
在linux下路径一般为:/usr/local/txt.txt。
3)通用用法
windows下的写法\\ 在linux下无法被识别,但是linux的 / 在windows下也可以被识别。所以可以用\来隔开。
还有File.separator()。这个更专业,在所有系统下通用。
如:
File.separator()+"demo"+File.separator()+"txt.txt"这样。

三、IO概述
io的中文名是输入/输入,英文为input/output。在计算机中,常用的io设备有磁盘,键盘,网络,显示器等,在操作系统层面有文件,网络,标准输入输出(对应键盘,显示器),管道等,而io就是来读写这些设备的。java有java.io和java.nio两套类库。
java.io是jdk1.4版本就有的,java.nio则是jdk1.4版本加入的。nio支持非阻塞io的开发,在jdk1.7中对nio类库进行了升级,支持异步非阻塞io的开发。
四、IO分类概述
根据数据的流向分为:输入流和输出流。
输入流 :把数据从其他设备上读取到内存的流。
输出流 :把数据从内存中写出到其他设备上的流。
根据数据的类型分为:字节流和字符流。
字节流 :以字节为单位,读写数据的流。
字符流 :以字符为单位,读写数据的流。
| 输入流 | 输出流 | |
| 字节流 | 字节输入流 InputStream | 字节输出流 OutputStream |
| 字符流 | 字符输入流 Reader | 字符输出流 Writer |

五、基础类用法
1)字节流
字节流的意思很明显,就是以数库类型为byte的流,而计算机系统底层都是以二进制进行存储的,那么字节流可以传输任意文件。
字节输出流
java.io.OutputStream是所有字节输出流的超类。其主要方法为
public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
public abstract void write(int b) :将指定的字节输出流。
FileOutputStream类
构造方法:
public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。
public FileOutputStream(File file, boolean append)
public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。
public FileOutputStream(String name, boolean append) 注意这个,默认append为false,每次输出都会覆盖文件,当为true时不会覆盖而是往后添加。
1、写出字节:write(int b) 方法,每次可以写出一个字节数据
2、写出字节数组:write(byte[] b),每次可以写出数组中的数据
3、写出指定长度字节数组:write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节
示例:
// 使用File对象创建流对象
File file = new File("a.txt");
FileOutputStream fos = new FileOutputStream(file);
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("b.txt");
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 写出数据:虽然参数为int类型四个字节,但是只会保留一个字节的信息写出
fos.write(97); // 写出第1个字节
fos.write(98); // 写出第2个字节
fos.write(99); // 写出第3个字节
// 关闭资源
fos.close();
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "你好中国".getBytes();
// 写出字节数组数据
fos.write(b);
// 关闭资源
fos.close();
// 使用文件名称创建流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
// 字符串转换为字节数组
byte[] b = "abcde".getBytes();
// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
fos.write(b,2,2);
// 关闭资源
fos.close();
字节输入流
java.io.InputStream是所有输入流的超类,其主要方法为
public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
public abstract int read(): 从输入流读取数据的下一个字节。
public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
public int available(); 返回输入流中字节的长度。
FileInputStream类
构造方法:
FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
1、读取字节:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
2、使用字节数组读取:read(byte[] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1
示例:
// 使用File对象创建流对象
File file = new File("a.txt");
FileInputStream fos = new FileInputStream(file);
// 使用文件名称创建流对象
FileInputStream fos = new FileInputStream("b.txt");
// 使用文件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 读取数据,返回一个字节
int read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
read = fis.read();
System.out.println((char) read);
// 读取到末尾,返回-1
read = fis.read();
System.out.println( read);
// 关闭资源
fis.close();
// 使用文件名称创建流对象
FileInputStream fis = new FileInputStream("read.txt");
// 定义变量,保存数据
int b ;
// 循环读取
while ((b = fis.read())!=-1) {
System.out.println((char)b);
}
// 关闭资源
fis.close();
// 使用文件名称创建流对象.
FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
// 定义变量,作为有效个数
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组的有效字节部分,变成字符串打印
System.out.println(new String(b,0,len));// len 每次读取的有效字节个数
}
//也可以 byte[] c = new byte[fis.available]; 就可以一次全读取了,字符流没有这个
// 关闭资源
fis.close();
2)字符流
字符流以字符为数据类型传输的流,字符流需要注意字符编码的问题
字符输入流
java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read(): 从输入流读取一个字符。
public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
FileReader类
构造方法
FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。
构造时使用系统默认的字符编码和默认字节缓冲区。
- 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。
idea中UTF-8 - 字节缓冲区:一个字节数组,用来临时存储字节数据。
1、读取字符:read方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1,循环读取
2、使用字符数组读取:read(char[] cbuf),每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1
示例:
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
// 使用文件名称创建流对象
FileReader fr = new FileReader("read.txt");
// 定义变量,保存有效字符个数
int len ;
// 定义字符数组,作为装字符数据的容器
char[] cbuf = new char[2];
// 循环读取
while ((len = fr.read(cbuf))!=-1) {
System.out.println(new String(cbuf,0,len));
}
// 关闭资源
fr.close();
字符输出流
java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字符输出流的基本共性功能方法。
void write(int c)写入单个字符。void write(char[] cbuf)写入字符数组。abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。void write(String str)写入字符串。void write(String str, int off, int len)写入字符串的某一部分,off字符串的开始索引,len写的字符个数。void flush()刷新该流的缓冲。void close()关闭此流,但要先刷新它。
FileWriter类
FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。FileWriter(String fileName, boolean append)同字节流,默认覆盖,true时为添加
构造时使用系统默认的字符编码和默认字节缓冲区。
1、写出字符:write(int b) 方法,每次可以写出一个字符数据
2、写出字符数组 :write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以写出字符数组中的数据,用法类似FileOutputStream
3、写出字符串:write(String str) 和 write(String str, int off, int len) ,每次可以写出字符串中的数据,更为方便
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。
示例:
// 使用File对象创建流对象
File file = new File("fw.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('C'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。
/*
【注意】关闭资源时,与FileOutputStream不同。
如果不关闭,数据只是保存到缓冲区,并未保存到文件。
*/
// fw.close();
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据,通过flush
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('关'); // 写出第1个字符
fw.close();
fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
fw.close();
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串转换为字节数组
char[] chars = "你好中国".toCharArray();
// 写出字符数组
fw.write(chars);
// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
fw.write(b,2,2); //中国
// 关闭资源
fos.close();
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 字符串
String msg = "你好中国";
// 写出字符数组
fw.write(msg); //你好中国
// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
fw.write(msg,2,2); // 中国
// 关闭资源
fos.close();
3)缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流:
BufferedInputStream,BufferedOutputStream - 字符缓冲流:
BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

如果每次读写是大于或等于8kb即8192字节,那么缓冲流不会有性能上的优势,甚至会更慢。
另外缓冲流的输出文件是否拼接,由里面的OutputStream, Writer决定。
字节缓冲流
构造方法:
public BufferedInputStream(InputStream in):创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流。
示例:
// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
字符缓冲流
构造方法
public BufferedReader(Reader in):创建一个 新的缓冲输入流。public BufferedWriter(Writer out): 创建一个新的缓冲输出流。
示例:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
- BufferedReader:
public String readLine(): 读一行文字。 - BufferedWriter:
public void newLine(): 写一行行分隔符,由系统属性定义符号。
示例1:
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
示例2:
// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 写出数据
bw.write("hello");
// 写出换行
bw.newLine();
bw.write("world");
bw.newLine();
bw.write("!");
bw.newLine();
// 释放资源
bw.close();
4)转换流
在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
示例:
public class ReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("E:\\File_GBK.txt");
int read;
while ((read = fileReader.read()) != -1) {
System.out.print((char)read);
}
fileReader.close();
}
}
输出结果:
���
那么如何读取GBK编码的文件呢?

InputStreamReader类
转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。
示例:
// 定义文件路径,文件为gbk编码
String FileName = "E:\\file_gbk.txt";
// 创建流对象,默认UTF8编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
// 创建流对象,指定GBK编码
InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
// 定义变量,保存字符
int read;
// 使用默认编码字符流读取,乱码
while ((read = isr.read()) != -1) {
System.out.print((char)read); // ��Һ�
}
isr.close();
// 使用指定编码字符流读取,正常解析
while ((read = isr2.read()) != -1) {
System.out.print((char)read);// 大家好
}
isr2.close();
OutputStreamWriter类
转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
构造方法
OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。
示例:
// 定义文件路径
String FileName = "out.txt";
// 创建流对象,默认UTF8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
// 写出数据
osw.write("你好"); // 保存为6个字节
osw.close();
// 定义文件路径
String FileName2 = "out2.txt";
// 创建流对象,指定GBK编码
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
// 写出数据
osw2.write("你好");// 保存为4个字节
osw2.close();
StandardCharsets 标准的字符编码常量类。

5)序列化
https://blog.51cto.com/u_16175463/8684056 序列化的serialVersionUID
Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。

ObjectOutputStream类
java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
序列化操作
一个对象要想序列化,必须满足两个条件:
- 必须实现Serializable接口。
- 必须保证其所有属性均可序列化。(transient修饰为临时属性,不参与序列化)
写出对象方法
public final void writeObject (Object obj): 将指定的对象写出。
示例:
public class Employee implements java.io.Serializable {
public String name;
public String address;
public transient int age; // transient瞬态修饰成员,不会被序列化
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
public class SerializeDemo{
public static void main(String [] args) {
Employee e = new Employee();
e.name = "zhangsan";
e.address = "guangzhou";
e.age = 20;
try {
// 创建序列化流对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
// 写出对象
out.writeObject(e);
// 释放资源
out.close();
fileOut.close();
System.out.println("序列化完成"); // 姓名,地址被序列化,年龄没有被序列化。
} catch(IOException i) {
i.printStackTrace();
}
}
}
ObjectInputStream类
ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
反序列化操作
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法,
public final Object readObject () : 读取一个对象。
示例:
public class DeserializeDemo {
public static void main(String [] args) {
Employee e = null;
try {
// 创建反序列化流
FileInputStream fileIn = new FileInputStream("employee.txt");
ObjectInputStream in = new ObjectInputStream(fileIn);
// 读取一个对象
e = (Employee) in.readObject();
// 释放资源
in.close();
fileIn.close();
}catch(IOException i) {
// 捕获其他异常
i.printStackTrace();
return;
}catch(ClassNotFoundException c) {
// 捕获类找不到异常
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
// 无异常,直接打印输出
System.out.println("Name: " + e.name); // zhangsan
System.out.println("Address: " + e.address); // beiqinglu
System.out.println("age: " + e.age); // 0
}
}
注意:
对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。
当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。
发生这个异常的原因,该类的序列版本号与从流中读取的类描述符的版本号不匹配 ,serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
serialVersionUID是一个非常重要的字段,因为 Java 的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。
一般来说,定义serialVersionUID的方式有两种,分别为:
采用默认的1L,具体为private static final long serialVersionUID = 1L;
在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。
1->2->3.....
根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,例如 private static final long serialVersionUID = XXXL;
这种方式适用于这样的场景:
开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid声明语句,再自动生成一下。
第二种能够保证每次更改类结构后改变版本号,但还是要手工去生成
示例:
public class Employee implements java.io.Serializable {
// 加入序列版本号
private static final long serialVersionUID = 1L;
public String name;
public String address;
// 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
public int eid;
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
6)Properties属性类
常用方法
public Object setProperty(String key, String value): 保存一对属性。public String getProperty(String key):使用此属性列表中指定的键搜索属性值。public Set<String> stringPropertyNames():所有键的名称的集合。public void load(InputStream inStream): 从字节输入流中读取键值对。
示例1:
// 创建属性集对象
Properties properties = new Properties();
// 添加键值对元素
properties.setProperty("filename", "a.txt");
properties.setProperty("length", "123");
properties.setProperty("location", "D:\\a.txt");
// 打印属性集对象
System.out.println(properties);
// 通过键,获取属性值
System.out.println(properties.getProperty("filename"));
System.out.println(properties.getProperty("length"));
System.out.println(properties.getProperty("location"));
// 遍历属性集,获取所有键的集合
Set<String> strings = properties.stringPropertyNames();
// 打印键值对
for (String key : strings ) {
System.out.println(key+" -- "+properties.getProperty(key));
}
示例2:
// 创建属性集对象
Properties pro = new Properties();
// 加载文本中信息到属性集
pro.load(new FileInputStream("read.txt"));
// 遍历集合并打印
Set<String> strings = pro.stringPropertyNames();
for (String key : strings ) {
System.out.println(key+" -- "+pro.getProperty(key));
}
六、按装饰类与原装类进行区分
除了根据数据的流向,以及数据的类型进行区分,还可以按以下方式用装饰器类和原装类进行区分。

1)原始类:
文件类:
字节流:FileInputStream, FileOutPutStream
字符流:FileReader, FileWriter
网络:
io没有专门用于网络的类,一般配合java.net类库,直接使用InputStream,OutputStream进行读写。

内存:
字节流:ByteArrayInputStream,ByteArrayOutputStream
字符流:CharArrayReader,CharArrayWriter
在做单元测试,或者处理第三方的流时,可以直接将其转换成上面的,没必要再封装成文件或什么来操作。
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(out);
new Thread(new Runnable() {
@Override
public void run() {
try {
out.write("Hi wangzheng~".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
byte[] buffer = new byte[512];
try {
in.read(buffer);
System.out.println(new String(buffer));
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
管道
字节流:PipedInputStream、PipedOutputStream、
字符流:PipedReader、PipedWriter
管道是Java提供的为同一个进程内两个线程之间通信的工具,一个线程通过PipedOutputStream写入的数据,另一个线程就可以通过PipedInputStream读取数据,示例代码如下所示
标准输入输出
在操作系统中,一般会有三个标准I/O系统:标准输入、标准输出、标准错误输出。标准输入对应I/O设备中的键盘,标准输出和标准错误输出对应I/O设备中的屏幕。Java中的标准输入为System.in,它是一个定义在System类中的静态InputStream对象。Java中的标准输出和标准错误输出分别为System.out和System.err,它们都是定义在System类中的PrintStream对象。PrintStream为装饰器类,需要嵌套OutputStream来使用,支持按照格式输出数据,System.in、System.out、System.err的使用示例如下所示。
Scanner s = new Scanner(System.in);
System.out.println("echo: " + s.nextLine());
//System.err显示的字符串为红色,以表示出错
System.err.println("echo: " + s.nextLine());
2)装饰器类
装饰器类一般用于对原始类的增强
支持读写缓存功能的装饰器类
BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter
上面基础类用法已经说过
支持基本类型数据读写的装饰器类
DataInputStream支持将从输入流中读取的数据解析为基本类型(byte、char、short、int、float、double等),DataOutputStream类支持将基本类型数据转化为字节数组写入输出流。示例代码如下所示。
DataOutputStream out = new DataOutputStream(new FileOutputStream("/Users/wangzheng/a.txt"));
out.writeInt(12);
out.writeChar('a');
out.writeFloat(12.12f);
out.close();
DataInputStream in = new DataInputStream(new FileInputStream("/Users/wangzheng/a.txt"));
System.out.println(in.readInt());
System.out.println(in.readChar());
System.out.println(in.readFloat());
in.close();
调用DataOutputStream的readChar()、writeChar()函数,我们也可以按字符为单位读取、写入数据,但跟字符流类不同的地方是,DataOutputStream类一次只能处理一个字符,而字符流类可以处理char数组,并且字符流类提供的函数更多,功能更加丰富。
支持对象读写的装饰器类
即上面的序列化ObjectInputStream和ObjectOutputStream.
支持格式化打印数据的装饰器类
PrintStream和PrintWriter可以将数据按照一定的格式,转化为字符串,写入到输出流。前面讲到System.out、System.err就是PrintStream类型的。示例代码如下所示。
PrintStream printStream =new PrintStream(new FileOutputStream("/Users/wangzheng/a.txt"));
printStream.print(124); //int->Integer->toString(), 写入字符串"124"
printStream.printf("hello %d", 43); //写入字符串"hello 43"
特殊的装饰器类
即上面的转换流
正常应该是字节流原始类对字节流的装饰器类,字符流对字符流的装饰器类
而此处字符流的装饰器类,用了字节流的原始类。
1297

被折叠的 条评论
为什么被折叠?



