1.字节输出流
输出流:
OutputStream(抽象类)
FileOutputStream(基本输出流)
构造方法:
public FileOutputStream(String name):创建输出流操作的目标
public FileOutputStream(String name,boolean append):append为true代表每次写入都向文件末尾追加,为false则每次都是覆盖写入
操作方法:
write(int n):输出一个字节;
write(byte[] b):输出一个字节数组;
write(byte[] b, int off , int len):输出字节数组的一部分;
close(): 释放IO占用的windows底层资源;
public void write(byte[] b) 写出一个字节数组的字节
- 输出流的源代码实现:如果输出时没有该文件,则会先创建该文件,再输出数据
- 默认的写出是覆盖掉了文件以前的内容,如果想每次运行程序写出数据不覆盖之前的内容,使用特定的构造方法
- public FileOutputStream(String name,boolean append) append参数:是否追加数据
- 在FileOutputStream的构造方法当中,指定的io资源可以是文件对象,也可以是文件路径,其本质是相同的.
- 一般情况下直接使用给予文件路径的方式创建IO流对象,因为源代码中会自动帮助我们创建File对象. ```java package com.igeek_01;
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashSet; import java.util.Set;
/**
- @author Lynn
@create 2020-12-11-10:20 / public class FileOutPutStreamDemo { /public static void main(String[] args) throws IOException {
//创建流对象,绑定io数据
FileOutputStream fos=new FileOutputStream("test.txt");
//向文件中写入数据
// fos.write(0b01100001);//当前输入的是一个a的二进制字节码 // fos.write(98);
fos.write('a');
//关闭流
fos.close();
}*/
/*public static void main(String[] args) throws IOException {
//创建一个流对象
FileOutputStream fos=new FileOutputStream("test.txt",true);//支持追加
//写入数据
byte[] b={97,98,99};
fos.write(b);
//int类型的数组不支持,因为方法的参数中只传入byte类型的数组
*//*int[] i={100,101,102};
fos.write(i);*//*
fos.close();
字节输入流
输入流:
InputStream(抽象类):
FileInputStream(基本输入流)
构造方法:
public FileInputStream(String name)
操作方法:
int read():读取一个字节, 返回的是字节内容本身,读取到末尾返回-1
int read(byte[] b):读取一个字节数组
close():释放IO占用的系统底层资源 ```java package com.igeek_02;
import java.io.FileInputStream; import java.io.IOException;
/**
- @author Lynn
@create 2020-12-11-10:34 */ public class InputStreamDemo { public static void main(String[] args) throws IOException {
//创建文件输入流--保证文件必须存在
FileInputStream fis=new FileInputStream("test.txt");
/*//读取
int c= fis.read();
System.out.println(c);//97
System.out.println(Integer.toBinaryString(c));//1100001--97的二进制换算*/
/*//逐个读取--底层有一个指针,进行逐个读取
System.out.println(fis.read());//97
System.out.println(fis.read());//97
System.out.println(fis.read());//98
System.out.println(fis.read());//99
System.out.println(fis.read());//-1---读完了,没有了*/
//循环读取
int c=-1;//没有内容可读
while ((c= fis.read())!=-1){
// System.out.println(c+” “);
System.out.println((char)c+" ");
}
fis.close();
} } ``` 一次读取一个字节数组
- int read(byte[] b):读取一个字节数组
返回值是本次读取到的字节的个数
参数用于每次存储字节数据的数组
```java package com.igeek_02;读取到文件末尾返回-1
import java.io.FileInputStream; import java.io.IOException; import java.util.Arrays;
/**
- @author Lynn
@create 2020-12-11-10:42 */ public class InputStreamDemo2 { public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("test.txt");
/*//封装一个数组--byte
byte[] b=new byte[3];
int len= fis.read(b);
System.out.println(len);//确定一次性读取的数组的长度是3
System.out.println(Arrays.toString(b));//[97,98,99]--数组的内容*/
//循环读取
byte[] bytes=new byte[3];
int len=-1;//说明没有内容了
while ((len= fis.read(bytes))!=-1){
String s=new String(bytes,0,len);
System.out.println(s);
}
fis.read();
高效流
Java在常规IO流的基础上,提供了更为高效的缓冲流,如下:
高效字节缓冲流:BufferedInputStream/BufferedOutputStream
高效流使用普通流对象作为构造方法参数。将普通流包装,提供高效的装饰。
高效流write写出数据时,写出位置为缓冲区,并非目标资源。需要通过flush刷新方法将缓冲区的内容写出到目标文件中。
高效输出流的关闭方法会自动调用flush方法。 ```java package com.igeek_02;
/**
- @author Lynn
- @create 2020-12-11-11:06 */
import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;
/**
- 高效流—高级流
- 原理:缓存区临时存放多个数据,一次性调用底层的资源,减少调用的次数,从而提升程序运行的效率
- 所以在高级流的底层需要一个低级流作为支撑 *
- 高效字节流的api:
- BufferedInputStream/BufferedOutputStream *
- 高效流和普通流基本(完全)一样
- 高效流使用普通流作为构造函数的参数,在普通流的基础上增加缓存区 *
- 高效write写出的时候,写出的位置是在缓存区,并不是目标资源
- 需要通过flush()方法将缓存区中的内容写出到目标资源中—目的是提高效率 *
- 方法:
- void flush()—刷新缓存区
void close()—关闭流,关闭前调用flush方法 */ public class BufferedStreamDemo { public static void main(String[] args) throws IOException {
//以高效字节输出流为例
//1.创建普通字节流
FileOutputStream fos=new FileOutputStream("test.txt");
//2.通过高效流使用普通流---将普通流作为参数参入高效流的构造函数
BufferedOutputStream bos=new BufferedOutputStream(fos);
//利用高效流处理数据
bos.write(97);
bos.write(new byte[]{100,101,102});
//刷新缓存区
bos.flush();
//关闭流--直接关闭高效流即可,普通流会随之关闭
bos.close();
高效流使用案例1
```java package com.igeek_02;
/**
- @author Lynn
- @create 2020-12-11-11:17 */
import java.io.*;
/**
高效流使用案例 */ public class BufferedWriterReaderDemo { public static void main(String[] args) throws IOException {
//1.创建普通流
FileWriter fw=new FileWriter("test2.txt");
//2.创建高效流--将普通流作为参数传入--对应FileWriter
BufferedWriter bw=new BufferedWriter(fw);
//写入数据
bw.write("天空飘来五个字");//支持字符,因为是BufferedWriter中的
//刷新缓存区
bw.flush();
//关闭流
bw.close();
System.out.println("---------------------------------------");
//1.创建普通流--保证文件存在
FileReader fr=new FileReader("test2.txt");
//2.创建高效流--将普通流作为参数传入--对应FileWriter
BufferedReader br=new BufferedReader(fr);
//读出数据
char[] chs=new char[1024];
//获取读取字符的个数
int len=br.read(chs);
//将字符转换成字符串
String s=new String(chs,0,len);
System.out.println(s);
//关闭流
br.close();
高效流使用案例2
特殊方法(属于高效流的)
- public void readLine()—读取一行,读到末尾的时候返回null ```java package com.igeek_02;
/**
- @author Lynn
- @create 2020-12-11-11:17 */
import java.io.*;
/**
- 高效流使用案例 *
- 特殊方法(属于高效流的)
public void readLine()—读取一行,读到末尾的时候返回null */ public class BufferedWriterReaderDemo { public static void main(String[] args) throws IOException {
//1.创建普通流
FileReader fr=new FileReader("test3.txt");
//2.创建高效流--将普通流作为参数传入--对应FileWriter
BufferedReader br=new BufferedReader(fr);
//读取操作--每次读取一行
/* System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());
System.out.println(br.readLine());//null */
//循环读取
String s=null;//必须写成null,不能用 s=""
while ((s=br.readLine())!=null){
//输出的是一行
System.out.println(s);
}
//关闭流
br.close();
System.out.println("---------------------------------------");
}
}
<a name="aNVH7"></a>
### 演示流传输中编码的问题

```java
package com.igeek_02;
import java.io.*;
/**
* @author Lynn
* @create 2020-12-14-9:57
*/
public class CharacterDemo {
public static void main(String[] args) throws IOException {
//使用utf-8格式输出到文件中,文件使用gbk观看乱码,使用utf-8就正常
FileOutputStream fos=new FileOutputStream("test5.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"gbk");
//写入数据
osw.write("你好");
osw.close();
//读出
FileInputStream fis=new FileInputStream("test5.txt");
InputStreamReader isr=new InputStreamReader(fis,"utf-8");
System.out.println((char)isr.read());
System.out.println((char)isr.read());
isr.close();
}
}
高效流练习
package com.igeek_02;
/**
* @author Lynn
* @create 2020-12-14-9:30
*/
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
/**
* 练习
*
* 需求:
* 将test4.txt中的所有的名称进行读取,并且倒序再次输入到test.txt中
*
* 步骤:
* 1.定义一个集合存储名字
* 2.使用高效流一次读取一行
* 3.将读取的名字放到集合中
* 4.使用工具类中的反排序方法--reverse
* 5.使用高级流依次写出一个名字
*/
public class Test {
public static void main(String[] args) throws IOException {
//流 处理
FileReader fr=new FileReader("test4.txt");
BufferedReader br=new BufferedReader(fr);
//定义一个集合
ArrayList<String> list=new ArrayList<>();
//一次读取一个名字
String s=null;
while ((s=br.readLine())!=null){
//查看文档中的数据
System.out.println(s);
//保存到集合
list.add(s);
}
//关闭流
br.close();
//使用工具类中的反排序方法--reverse
Collections.reverse(list);
//使用高级流写出
FileWriter fw=new FileWriter("test4.txt");
BufferedWriter bw=new BufferedWriter(fw);
//写出操作
for (String name:list){
//将每一个名字放到test4.txt
bw.write(name);
//换行--相当于加一个回车
bw.newLine();
}
//关闭流
bw.close();
}
}
文件复制
文件复制不使用字节数组
利用字节流将当前工程下的ASCII码表完整版.doc复制到当前工程下的ASCII码表完整版(副本).doc
案例代码六:
A:分析:
最终两个文件中的数据一致
1. 利用字节输入流关联ASCII码表完整版.doc文件
2. 利用字节输出流关联ASCII码表完整版(副本).doc文件
3. 循环从ASCII码表完整版.doc读一个字节,然后将这个字节写入到ASCII码表完整版(副本).doc,直到读到ASCII码表完整版.doc的末尾
package com.igeek_01;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClassName: CopyFileDemo
* @Description: 文件复制不使用字节数组
* @date 2017年11月23日 上午8:58:46
* Company www.igeekhome.com
*
* 分析:
* 1. 利用字节输入流关联ASCII码表完整版.doc文件
* 2. 利用字节输出流关联ASCII码表完整版(副本).doc文件
* 3. 循环从ASCII码表完整版.doc读一个字节,
* 然后将这个字节写入到ASCII码表完整版(副本).doc,
* 直到读到ASCII码表完整版.doc的末尾
* 即先读后写
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
//使用一次一个字节的方式完成复制
//创建IO流对象绑定IO资源
FileInputStream fis = new FileInputStream("ASCII码表完整版.doc");
FileOutputStream fos = new FileOutputStream("ASCII码表完整版(副本).doc");
//读取数据,读一个字节,写一个字节
//先读
//定义变量c,用于存储每次读取到的字节
int c=-1;
while((c=fis.read())!=-1) {
//后写
fos.write(c);
}
//关闭流
fos.close();
fis.close();
}
}
文件复制使用字节数组
利用字节流和字节数组将当前工程下的ASCII码表完整版.doc复制到当前工程下的ASCII码表完整版(副本).doc
案例代码七:
A:分析:
最终两个文件中的数据一致
1. 定义一个长度为1024整数倍的字节数组
2. 利用字节输入流关联ASCII码表完整版.doc文件
3. 利用字节输出流关联ASCII码表完整版(副本).doc文件
4. 循环从ASCII码表完整版.doc读一个字节数组,然后将这个字节数组中有效的内容写入到ASCII码表完整版(副本).doc,直到读到ASCII码表完整版.doc的末尾
package com.igeek_02;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @ClassName: CopyFileDemo
* @Description: 文件复制使用字节数组
* @date 2017年11月23日 上午9:05:23
* Company www.igeekhome.com
*
* 分析:
* 1. 定义一个长度为1024整数倍的字节数组
* 2. 利用字节输入流关联ASCII码表完整版.doc文件
* 3. 利用字节输出流关联ASCII码表完整版(副本).doc文件
* 4. 循环从ASCII码表完整版.doc读一个字节数组,
* 然后将这个字节数组中有效的内容写入到ASCII码表完整版(副本).doc,
* 直到读到ASCII码表完整版.doc的末尾
* 即先读后写
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
//使用一次一个字节数组的方式完成复制
//创建IO流对象绑定IO资源
FileInputStream fis = new FileInputStream("ASCII码表完整版.doc");
FileOutputStream fos = new FileOutputStream("ASCII码表完整版(副本).doc");
//读取数据,读一个字节数组,写一个字节数组
//定义字节数组,用于存储每次读取到的数据
byte[] bytes = new byte[1024];
//定义变量,用于记录每次读取到数据的长度
int len=-1;
//先读
while((len = fis.read(bytes))!=-1) {
//后写
fos.write(bytes,0,len);
}
//关闭流
fos.close();
fis.close();
}
}
转换流
Reader:
InputStreamReader可以完成字节输入流转换为字符输入流
Writer:
OutputStreamWriter可以完成字节输出流转换为字符输出流
package com.igeek_01;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/**
* @ClassName: OutputStreamWriterDemo
* @Description: OutputStreamWriter的使用
* @date 2017年11月23日 上午10:47:22
* Company www.igeekhome.com
*
* 需求:
* 已经具备字节流,绑定了IO资源
* 需要将字节流转成字符流
*
* 此时,可以使用转换流,接收一个字节流对象,进行字符流的操作.
* 转换流本身就是字符流
*
* 转换流:
* Reader:
* InputStreamReader可以完成字节输入流转换为字符输入流
* Writer:
* OutputStreamWriter可以完成字节输出流转换为字符输出流。
*
* 则转换流的使用方法:
* 构造方法传入字节流对象
* 自身调用字符流的方法
*/
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//创建字节输出流
FileOutputStream fos = new FileOutputStream("test.txt");
//将字节流转为字符流,即通过字节流对象创建转换流对象
OutputStreamWriter osw = new OutputStreamWriter(fos);
//使用字符流的方法
osw.write("hello:中国");
//与高效流类似,转换流包含字节流,所以直接关闭转换流,字节流也关闭了
osw.close();
}
}
package com.igeek_01;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @ClassName: InputStreamReaderDemo
* @Description: InputStreamReaderDemo的使用
* @date 2017年11月23日 上午10:55:03
* Company www.igeekhome.com
*
* 需求:
* 已经具备字节流,绑定了IO资源
* 需要将字节流转成字符流
*
* 此时,可以使用转换流,接收一个字节流对象,进行字符流的操作.
* 转换流本身就是字符流
*
* 转换流:
* Reader:
* InputStreamReader可以完成字节输入流转换为字符输入流
* Writer:
* OutputStreamWriter可以完成字节输出流转换为字符输出流。
*
* 则转换流的使用方法:
* 构造方法传入字节流对象
* 自身调用字符流的方法
*/
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//对比字节流操作字符与字符流操作字符的区别
//普通字节流
FileInputStream fis = new FileInputStream("test.txt");
int b=-1;
while((b=fis.read())!=-1) {
System.out.println((char)b);
}
fis.close();
System.out.println("=====================");
//字符流(这里使用转换流转成一个字符流)
FileInputStream fis2 = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis2);
int c=-1;
while((c=isr.read())!=-1) {
System.out.println((char)c);
}
isr.close();
}
}
序列化和反序列化
用于向流中写入对象的操作流 ObjectOutputStream称为序列化流
用于从流中读取对象的操作流 ObjectInputStream称为反序列化流
特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。
ObjectOutputStream序列化流
public final void writeObject(Object obj)
ObjectInputStream反序列化流
public final Object readObject()
每个被序列化操作的类型必须实现Serializable接口(具备序列化功能的标记接口),让其具备序列化能力。
package com.igeek_03;
/**
* @author Lynn
* @create 2020-12-14-10:18
*/
import java.io.Serializable;
/**
* 序列化和反序列化:
* 序列化:利用序列化流将一个对象的整体转换为二进制的数据,并且存储到文件中
* 将对象永久性的存入一个文件,叫做序列化,读取的过程叫做反序列化
*
* 对象是需要封装的,为了实现对象的序列化,我们要将对象实现一个序列化接口--Serializable
* 这个接口中没有方法,就是一个规范,只要实现了这个接口,那么序列化的时候就不会出现问题
*
* 序列化版本号:序列化ID(serialVersionUID),用于记录对象的类型
* 每一个被序列化的操作对象操作其对象上午ID与接收类型的ID必须一致
* 序列化的ID和反序列化的ID必须一致
*
* 封装一个开发级别的实体类(标准的)
* 1.必须实现序列化接口--声明UID
* 2.属性私有化,并且声明get/set方法
* 3.声明无参有参构造函数
* 4.重写HashCode和equals方法
* 5.重写toString方法
*
* 拓展:
* transient关键字在序列化中的使用:是一个修饰符,被修饰的属性可以在序列化中被忽略,
* 在某些特定的业务场景会使用
*/
class Person_up implements Serializable {
private static final long serialVersionUID = 324576945194316948L;
/**
* serialVersionUID:生成的标准的唯一的码
*/
// private static final long serialVersionUID=;
//定义普通的标识码--普通版本码
// private static final long serialVersionUID=1L;
private String name;
//这个age就不会被序列化
private transient int age;
public Person_up() {
}
public Person_up(String name, int age) {
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 +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person_up person = (Person_up) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
package com.igeek_03;
/**
* @author Lynn
* @create 2020-12-14-10:35
*/
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
/**
* 序列化对象
*
* 序列化流:
* ObjectOutputStream:序列化流(对象输出流)
* public final void writeObject(Object obj)
*
* ObjectInputStream:反序列化流(对象输入流)
* public final Object readObject()
*/
public class SerializableDemo {
public static void main(String[] args) throws IOException {
//准备被序列化的对象
Person_up p=new Person_up("jack",18);
//进行序列化操作
FileOutputStream fos=new FileOutputStream("person_up.txt");
ObjectOutput oos=new ObjectOutputStream(fos);
//开始序列化
oos.writeObject(p);
//关闭流
oos.close();
}
}
package com.igeek_03;
/**
* @author Lynn
* @create 2020-12-14-10:35
*/
import java.io.*;
/**
* 序列化对象
*
* 序列化流:
* ObjectOutputStream:序列化流(对象输出流)
* public final void writeObject(Object obj)
*
* ObjectInputStream:反序列化流(对象输入流)
* public final Object readObject()
*/
public class SerializableDemo2 {
public static void main(String[] args) throws IOException,Exception {
//进行反序列化操作--保证对象存在
FileInputStream fis=new FileInputStream("person_up.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
//开始反序列化
Person_up p=(Person_up) ois.readObject();
System.out.println(p.getName());
System.out.println(p.getAge());
System.out.println(p);
//关闭流
ois.close();
}
}
打印流
package com.igeek_04;
/**
* @author Lynn
* @create 2020-12-14-11:12
*/
import java.io.FileNotFoundException;
import java.io.PrintWriter;
/**
* 演示操作:
*
* 打印流(自动行刷新流):只有输出没有输入
* printStream:字节打印流,调用println方法自动刷新
* printwriter:字符打印流,指定自动化刷新开关后,调用println方法自动刷新,无需手动调用flush方法
* 每执行一次会自动刷新缓存区
* 在网络传输中使用很多
*/
public class PrintwriterDemo {
public static void main(String[] args) throws FileNotFoundException {
//创建对象
PrintWriter pw=new PrintWriter("test8.txt");
//println自带换行
pw.println("干饭啦");
pw.println("干饭啦");
pw.println("干饭啦");
pw.println("干饭啦");
pw.println("干饭啦");
pw.print("我是谁");
pw.print("\n");//制表符在这个打印方法中是有效的
pw.print("我是哪");
// pw.print("\\n");无效
pw.print("我在干什么");
pw.close();
}
}