IO流规律总结
1.要操作的是数据源还是数据目的
数据 | 字节操作类 | 字符操作类 |
---|---|---|
数据源 | InputStream(所有字节输入流的超类) | Reader(所有字符输入流的超类) |
数据目的 | OutputStream(所有字节输出流的超类) | Writer(所有字符输出流的超类) |
以上是IO的四大抽象基类
2.要操作的数据是字节还是文本
数据 | 源 | 目的 |
---|---|---|
字节 | InputStream | OutputStream |
文本 | Reader | Writer |
3.数据所在的具体设备
设备 | 源 | 目的 |
---|---|---|
硬盘 | 文件,File开头 | 文件,File开头 |
内存 | 数组,字符串 | 数组,字符串 |
键盘、屏幕 | System.in | System.out |
网络 | Socket | Socket |
4.是否需要额外功能
额外功能:是否需要转换(编码表),是否需要高效处理
源 | 目的 | |
---|---|---|
转换 | InputStreamReader | OutputStreamWriter |
高效 | BufferedReader,BufferedInputStream | BufferedWriter,BufferedOutputStream |
几个IO类
1.字节输入流
1.1 InputStream:所有字节输入流的超类。
read()方法
:
read()
:从输入流中读取数据的下一个字节。
read(byte[] b)
:从输入流中读取一定数量的字节,存储在缓冲区数组b中。
read(byte[] b, int off, int len)
:将输入流中最多len个数据字节读入byte数组。
1.2 FileInputStream:InputStream的子类,读取文件中的字节。
构造方法:
FileInputStream(File file):接收一个File对象指定目标文件。
FileInputStream(String name):使用字符串指定目标文件的路径。
1.3 BufferedInputStream: InputStream的子类,使用缓冲区读取文件中的字节。
由于使用了缓冲区,比FileInputStream类的读取效率更高。
构造方法:
BufferedInputStream(InputStream in) : 参数为InputStream的子类,一般是FileInputStream类。
2.字节输出流
2.1 OutputStream: 所有字节输出流的超类。
write()
方法:
write(int b)
: 将指定字节写入此输出流。
write(byte[] b)
: 将b.length个字节从指定的byte数组写入此输出流。
write(byte[] b, int off, int len
: 从b中的第off个元素开始写入len个字节。
2.2 FileOutputStream: OutputStream的子类,向文件中写入字节。
构造方法:
FileOutputStream(File file)
: 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
FileOutputStream(String name)
: 创建一个向具有指定名称的文件中写入数据的输出文件流。
2.3 BufferedOutputStream: OutputStream的子类,使用缓冲区向文件中写入字节。
由于使用了缓冲区,比FileOutputStream类的写入效率更高。
构造方法:
BufferedOutputStream(OutputStream out)
: 使用OutputStream的子类作为参数,一般是FileOutputStream类。
3. 字符输入流
3.1 Reader: 所有字符输入流的超类。
read()
方法:
read()
: 读取单个字符。
read(char[] cbuf)
:将字符读入数组。
3.2 FileReader: Reader的子类,读取文本文件。
构造方法:
FileReader(File file)
:接收一个File对象指定目标文件。
FileReader(String fileName)
:使用字符串指定目标文件的路径。
3.3 BufferedReader: Reader的子类,使用缓冲区读取文本文件。
由于使用了缓冲区,比FileReader类的读取效率更高。
构造方法:
BufferedReader(Reader in)
: 参数为Reader的子类,一般为FileReader。
独有方法String readLine()
:每次读取文本文件中的一行,读取到末尾时返回null。
4. 字符输出流
4.1 Writer: 所有字符输出流的超类。
write()
方法:
write(int c)
:写入单个字符。
write(char[] cbuf)
:写入字符数组。
write(char[] cbuf, int off, int len)
:写入字符数组的一部分。
write(String str)
:写入字符串。
write(String str, int off, int len)
:写入字符串的一部分。
flush()
方法:Writer类每次完成写入时都要进行刷新。
4.2 FileWriter:Writer的子类,向文本文件中写入字符。
构造方法:
FileWriter(File file)
FileWriter(String fileName)
4.3 BufferedWriter: Writer的子类,使用缓冲区向文本文件中写入字符。
构造方法:
BufferedWriter(Writer out)
newLine()
: 写入一个分隔符。
5.两个转换流
5.1 InputStreamReader:Reader的子类,是字节流通向字符流的桥梁。
构造方法:
InputStreamReader(InputStream in)
:参数为字节输入流InputStream的子类,使用默认编码表读取文件。
InputStreamReader(InputStream in, String charsetName)
:指定编码表读取文件(GBK、UTF-8)。
5.2 OutputStreamWritrer: Writer的子类,是字符流通向字节流的桥梁。
构造方法:
OutputStreamWriter(OuitputStream out)
: 参数为字节输出流OutputStream的子类,使用默认编码表写入文件。
OutputStreamWriter(OutputStream out, String charsetName)
:指定编码表写入文件(GBK、UTF-8)。
字节流实现文件复制
使用带有数组缓冲区的字节流实现文件复制的Java代码
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("d:\\a.pdf");
fos = new FileOutputStream("e:\\a.pdf");
// 定义一个字节数组,缓冲
byte[] bytes = new byte[1024];
// 读取数组,写入数组
int len = 0;
while((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
}catch(IOException ex){
System.out.println(ex);
throw new RuntimeException("文件复制失败");
}finally {
try {
if(fos != null)
fos.close();
}catch(IOException ex) {
throw new RuntimeException("释放资源失败");
}finally {
try {
if(fis != null)
fis.close();
}catch(IOException ex){
throw new RuntimeException("资源释放失败");
}
}
}
}
字符流实现文本文件复制
使用带有数组缓冲区的字符流实现文本文件复制。
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("d:\\1.txt");
fw = new FileWriter("e:\\1.txt");
char[] cbuf = new char[1024];
int len = 0;
while((len = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, len);
fw.flush();
}
}catch(IOException ex) {
System.out.println(ex);
throw new RuntimeException("复制失败");
}finally {
try {
if(fw != null) {
fw.close();
}
}catch (IOException ex) {
throw new RuntimeException("释放资源失败");
}finally {
try {
if(fr != null) {
fr.close();
}
}catch(IOException ex) {
throw new RuntimeException("释放资源失败");
}
}
}
}
集合Properties类
Properties类,继承Hashtable,实现Map接口。该类可以和IO对象结合使用,实现数据的永久存储。
主要Properties是没有泛型的,键和值的类型固定为String。
Properties pro = new Properties();
Properties的独有方法
setProperty(String key, String value)
:相当于Map接口中的put,将键值对存储到集合中。
getProperty(String key)
:通过键获取值。
stringPropertyNames()
:将集合中的键存储到Set集合,类似于Map接口中的keySet方法。
示例代码:
public static void function() {
Properties pro = new Properties();
pro.setProperty("a", "1");
pro.setProperty("b", "2");
pro.setProperty("c", "3");
System.out.println(pro);
String value = pro.getProperty("w");
System.out.println(value);
Set<String> set = pro.stringPropertyNames();
for(String key : set) {
System.out.println(key + "..." + pro.getProperty(key));
}
}
load()
:参数为load(InputStream in)
和load(Reader r)
,传递任意的字节输入流或字符输入流,将流对象中的键值对保存到集合中。目标文件的后缀必须是properties
public static void function1() throws IOException{
Properties pro = new Properties();
FileReader fr = new FileReader("d:\\pro.properties");
// 调用集合方法load传递字符输入流
pro.load(fr);
fr.close();
System.out.println(pro);
}
store
:参数为store(OutputStream out, String comments)
和store(Writer w, String comments)
,传递任意的字节输出流或字符输出流,将集合中的键值对写回到文件中。参数comments
是此次写入的注释。
public static void function_2() throws IOException {
Properties pro = new Properties();
pro.setProperty("name", "zhangsan");
pro.setProperty("age", "31");
pro.setProperty("email", "123456789@163.com");
FileWriter fw = new FileWriter("d:\\\\pro.properties");
// 键值对存回文件,使用集合store传递字符输出流
pro.store(fw, "");
fw.close();
}
ObjectStream:实现对象的序列化和反序列化
创建一个Person
类:一个类想要实现序列化必须实现Serializable接口。
注意:
1.静态成员变量无法序列化。
2.如果想要阻止一个非静态成员变量的序列化,可在声明时加transient关键字。
3.每次序列化一个类的对象时,如果改变了对象的内容,会为这个对象重新生成序列号。如果接收者反序列化对象时对象的序列号和序列化对象时对象的序列号不同,则反序列化会导致InvalidClassException,为避免这种异常,可声明一个static,final的long型字段显式声明自己的sriivalVersionUID。
public class Person implements Serializable{
private String name;
public transient/*阻止成员变量序列化*/ int age;
// 类自定义了序列号,编译器不会重新生成序列号
static final long serialVersionUID = 42L;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
1.objectOutputStream(OutputStream out)
:传递任意的字节输出流,写出对象。
void writeObject(Object obj)
写出对象方法。
public static void writeObject() throws IOException{
//创建字节输出流,封装文件
FileOutputStream fos = new FileOutputStream("d:\\person.txt");
//创建写出对象的序列化流的对象,构造方法传递字节输出流
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("lisi", 25);
//调用序列化流的方法writeObject写出对象
oos.writeObject(p);
oos.close();
}
2.ObjectInputStream(InputStream in)
:传递任意的字节输入流,输入流封装的文件必须是序列化的文件。
Object readObject()
:读取对象。
public static void readObject() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("d:\\person.txt");
// 创建反序列化流,构造方法中传递字节输入流
ObjectInputStream ois = new ObjectInputStream(fis);
// 调用反序列化犯法readObject()读取对象
Object obj = ois.readObject();
System.out.println(obj.toString());
ois.close();
}
打印流
- PrintStream
- PrintWriter
- 打印流的特点:
- 1.此流不负责数据源,只负责数据目的
- 2.为其他输出流添加功能
- 3.永远不会抛出IOException,但会抛出其他异常
- 两个打印流的方法完全一样
- 构造方法,就是打印流的输出目的端
PrintStream
:构造方法:接收File类型对象、字符串文件名、字节输出流对象OutputStreamPrintWriter
:构造方法:接收File类型对象、字符串文件名、字节输出流对象OutputStream、接收字符输出流Writer
/*
* 打印流,向File对象的数据目的写入对象
* 方法print println 原样输出
* write方法走码表
*/
public static void function() throws FileNotFoundException {
File file = new File("d:\\1.txt");
PrintWriter pw = new PrintWriter(file);
pw.println(100);
pw.flush();
pw.close();
}
/*
* 打印流,输出目的,String文件名
*/
public static void function_1() throws FileNotFoundException {
PrintWriter pw = new PrintWriter("d:\\2.txt");
pw.println(3.5);
pw.close();
}
/*
* 打印流,输出目的是流对象
* 可以是字节输出流,也可以是字符输出流
* OutputStream Writer
*/
public static void function_2() throws IOException {
FileWriter fw = new FileWriter("d:\\4.txt");
PrintWriter pw = new PrintWriter(fw);
pw.println("打印流");
pw.close();
}
/*
* 打印流printWriter可以开启自动刷新条件
* 满足两个条件:
* 1.数据目的必须是流对象
* OutputStream, Writer
* 2.必须调用println,printf,format
*/
public static void function_3() throws IOException{
FileOutputStream fos = new FileOutputStream("d:\\5.txt");
PrintWriter pw = new PrintWriter(fos, true);
pw.println("i");
pw.println("love");
pw.println("java");
pw.close();
}