流(Stream)就是计算机中数据的流动
IO流是单词Input Output Stream的缩写
Java提供了单独的一个包java.io来处理输入输出流
java.io包中定义了多个流类型(类或抽象类)来实现输入/输出功能
流的分类
-
从流的流动方向来看,可以将IO流分为输入流和输出流
-
从流的数据处理单位来看,可以将IO流分为字节流和字符流
-
从流的功能来看,还可以将IO流分为节点流和过滤流
流中保存的实际上全都是字节文件
数据进入到CPU叫输入流,从CPU出来叫输出流
数据进入CPU的操作叫读(read),从CPU出来叫写(write)
字节流
-
InputStream:字节输入流基类
-
OutputStream:字节输出流基类
字符流
-
Reader:字符输入流基类
-
Writer:字符输出流基类
简单操作输入输出流,目的是在"E:\\Demo2\\"目录下把a.txt的内容复制到b.txt
FileInputStream fis = new FileInputStream("E:\\Demo2\\a.txt");
FileOutputStream fos = new FileOutputStream("E:\\Demo2\\b.txt");
int len = 0;
byte[] b = new byte[2];
while((len = fis.read(b))!=-1) {
fos.write(b,0,len);
}
fos.close();
fis.close();
FileInputStream
FileOutputStream
FileOutStream在创建对象的时候如果没有这个文件它会帮我们创建,如果有这个文件它会帮我们清空文件中的数据
//当不想要清空数据时,只需要在第二个参数后面里面写true,表示将新数据追加在文件末尾
FileOutputStream fos = new FileOutputStream("a.txt",true);
// 创建一个File对象,存放的是更改的文件路径
File file1 = new File("E:\\test\\a.txt");// 文件内容为hello
// 写入的数据存放在b.txt中
File file2 = new File("E:\\test\\b.txt");
// 创建一个字节输出流,打开并连接到一个实际的文件file
FileInputStream fis = new FileInputStream(file1);
// 创建一个字节输入流,并写入到指定file2中
FileOutputStream fos = new FileOutputStream(file2);
// 每次读取2个字节的数据,当fis.read()不等于-1也就是文件里面还有内容的时候,继续循环重复读取2个字节的数据
byte[] b = new byte[2];
//len为读取的数据大小,一般时数组的长度
int len = 0;
while ((len = fis.read(b)) != -1) {
//从0开始,len为终点
fos.write(b, 0, len);
}
//关闭流
fos.close();
fis.close();
BufferedInputStream
BufferedOutputStream
// 创建一个File对象,存放的是更改的文件路径
File file1 = new File("E:\\test\\a.txt");// 文件内容为hello world
// 写入的数据存放在b.txt中
File file2 = new File("E:\\test\\b.txt");
// 创建一个字节输出流,打开并连接到一个实际的文件file
FileInputStream fis = new FileInputStream(file1);
// 创建一个字节输入流,并写入到指定file2中
FileOutputStream fos = new FileOutputStream(file2);
//缓冲区流包装文件输入流
BufferedInputStream bis = new BufferedInputStream(fis);
//缓冲区流包装文件输出流
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 每次读取2个字节的数据,当fis.read()不等于-1也就是文件里面还有内容的时候,继续循环重复读取2个字节的数据
byte[] b = new byte[2];
//len为读取的数据大小,一般时数组的长度
int len = 0;
while ((len = bis.read(b)) != -1) {
//从0开始,len为终点
bos.write(b, 0, len);
}
//关闭流
bos.close();
bis.close();
序列流
整合两个:SequenceInputStream(InputStream, InputStream)
FileInputStream fis1 = new FileInputStream("a.txt");
FileInputStream fis2 = new FileInputStream("b.txt");
SequenceInputStream sis = new SequenceInputStream(fis1, fis2);
FileOutputStream fos = new FileOutputStream("c.txt");
int len;
while ((len = sis.read()) != -1) {
fos.write(len);
}
sis.close();
fos.close();
整合多个:SequenceInputStream(Enumeration)
FileInputStream fis1 = new FileInputStream("a.txt");
FileInputStream fis2 = new FileInputStream("b.txt");
FileInputStream fis3 = new FileInputStream("c.txt");
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(fis1);
v.add(fis2);
v.add(fis3);
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("d.txt");
int len;
while ((len = sis.read()) != -1) {
fos.write(len);
}
sis.close();
fos.close();
内存输出流
ByteArrayOutputStream
-
该输出流可以向内存中写数据, 把内存当作一个缓冲区, 写出之后可以一次性获取出所有数据
-
可以使用toByteArray()
和toString()把数据从内存中取出来
-
可以不用关流
FileInputStream fis = new FileInputStream("a.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = fis.read()) != -1) {
baos.write(len);// 讲读取到的数据逐个写入内存
}
// byte[] byteArray = baos.toByteArray();//讲缓冲区的数据全部取出来,赋值给byteArray数组
// System.out.println(new String(byteArray));
System.out.println(baos.toString());// 直接打印内存中缓冲区里的数据
fis.close();
DataOutputStream
DataOutputStream
File file1 = new File("E:\\test\\a.txt");
FileOutputStream fos = new FileOutputStream(file1);
//创建数据输出流
DataOutputStream dos = new DataOutputStream(fos);
//写入8中基本数据类型数据
dos.writeByte((byte)1);
dos.writeShort((short)10);
dos.writeInt(100);
dos.writeLong(1000L);
dos.writeFloat(10000.1f);
dos.writeDouble(100000.2d);
dos.writeChar('A');
dos.writeBoolean(true);
//关闭流
dos.close();
fos.close();
//读取8个基本数据类型数据
FileInputStream fis = new FileInputStream(file1);
//创建数据输入流
DataInputStream dis = new DataInputStream(fis);
System.out.println("byte类型数据:"+dis.readByte());
System.out.println("short类型数据:"+dis.readShort());
System.out.println("int类型数据:"+dis.readInt());
System.out.println("long类型数据:"+dis.readLong());
System.out.println("float类型数据:"+dis.readFloat());
System.out.println("double类型数据:"+dis.readDouble());
System.out.println("char类型数据:"+dis.readChar());
System.out.println("boolean类型数据:"+dis.readBoolean());
//关闭流
dis.close();
fis.close();
PrintStream
File file1 = new File("E:\\test\\a.txt");
FileOutputStream fos = new FileOutputStream(file1);
//创建打印流
PrintStream ps = new PrintStream(fos);
//赋值变量
String name = "aaa";
int age = 18;
String sex = "男";
//打印数据到文件
ps.println("name:"+name);
ps.println("age:"+age);
ps.println("sex:"+sex);
//关闭流
ps.close();
结果:

ObjectInputStream:反序列化
ObjectOutputStraem:序列化
串行化必须实现Serializable接口
package Demo9;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable {
String name;
int age;
String sex;
public Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
public static void main(String[] args) throws Exception {
// 创建对象
Student student1 = new Student("aaa", 18, "男");
Student student2 = new Student("bbb", 19, "男");
Student student3 = new Student("ccc", 20, "男");
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
// 创建对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
// 写入对象
oos.writeObject(student1);
oos.writeObject(student2);
oos.writeObject(student3);
// 读取对象
Student stu1 = (Student) ois.readObject();
Student stu2 = (Student) ois.readObject();
Student stu3 = (Student) ois.readObject();
// 打印对象信息
System.out.println(stu1.toString());
System.out.println(stu2.toString());
System.out.println(stu3.toString());
// 关闭流
oos.close();
ois.close();
}
}
优化代码
// 创建对象,存入集合中
ArrayList<Student> list = new ArrayList<Student>();
list.add(new Student("aaa", 18, "男"));
list.add(new Student("bbb", 19, "男"));
list.add(new Student("ccc", 20, "男"));
// 创建对象输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
// 创建对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
// 写入集合对象
oos.writeObject(list);
// 读取集合对象
ArrayList<Student> listStudent = (ArrayList<Student>) ois.readObject();
// 打印对象信息
for (Student student : listStudent) {
System.out.println(student.toString());
}
// 关闭流
oos.close();
ois.close();
打印流
-
该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式
-
System.out就是一个PrintStream, 其默认向控制台输出信息
-
只操作数据目的
字节输出流
PrintStream ps = System.out;
ps.println(97); //其实底层用的是Integer.toString(x),将x转换为数字字符串打印
ps.println("xxx");
ps.println(new Person("张三", 23));
Person p = null;
ps.println(p); //如果是null,就返回null,如果不是null,就调用对象的toString()
字符输出流
PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true);
pw.write(97);
pw.print("大家好");
pw.println("你好"); //自动刷出,只针对的是println方法
pw.close();
标准流
System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据,流对象只有一个可以不用关
System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
修改输入流: System.setIn(InputStream)
修改输出流: System.setOut(PrintStream)
System.setIn(new FileInputStream("a.txt")); //修改标准输入流
System.setOut(new PrintStream("b.txt"));//修改标准输出流
InputStream in = System.in;//获取标准输入流,默认值向键盘,改变后指向a.txt
PrintStream ps = System.out;//获取标准输出流,默认值向控制台,改变后指向b.txt
int b;
while((b = in.read()) != -1) { //从a.txt上读取数据
ps.write(b); //将数据写到b.txt上
}
//System.out.println(); //平常打印语句不用关闭流,因为它没有跟文件关联
in.close();
ps.close(); //跟文件关联起来,所以要关流
随机访问流
RandomAccessFile
-
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
-
支持对随机访问文件的读取和写入。
-
在创建对象时不会清空文件里的数据
构造方法的第二个参数是对文件操作的权限:
RandomAccessFile baf = new RandomAccessFile("a.txt", "rw");
int read = baf.read();
System.out.println(read);
baf.seek(3); //在指定位置设置指针,控制读或者写,多线程下载时可以增加效率
baf.write(98);
baf.close();
Properties
-
主要做配置文件
-
Properties 类表示了一个持久的属性集。
-
Properties 可保存在流中或从流中加载。
-
属性列表中每个键及其对应值都是一个字符串。
Properties prop = new Properties();
prop.put("name", "张三");
prop.put("age", "20");
System.out.println(prop);
public Object setProperty(String key,String value)
public String getProperty(String key)
public Enumeration<String> stringPropertyNames()
Properties prop = new Properties();
prop.setProperty("name", "张三");
prop.setProperty("age", "20");
Enumeration<String> en = (Enumeration<String>) prop.propertyNames();
while (en.hasMoreElements()) {
String key = en.nextElement();
String value = prop.getProperty(key);
System.out.println(key + "=" + value);
}
Properties的load()和store()功能
Properties prop = new Properties();
prop.load(new FileInputStream("a.properties"));
prop.setProperty("name", "lisi");
prop.store(new FileOutputStream("a.properties"), null); // 第二个参数是对列表参数的描述,可以给值,也可以不给
System.out.println(prop);
字符流
-
字符流是可以直接读写字符的IO流
-
字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出.
-
不可以拷贝非纯文本的文件
FileReader
FileWriter
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int ch;
while((ch = fr.read()) != -1) {
fw.write(ch);
}
fr.close();
fw.close();
FileReader fr = new FileReader("aaa.txt"); //创建字符输入流,关联aaa.txt
FileWriter fw = new FileWriter("bbb.txt"); //创建字符输出流,关联bbb.txt
int len;
char[] arr = new char[1024*8]; //创建字符数组
while((len = fr.read(arr)) != -1) { //将数据读到字符数组中
fw.write(arr, 0, len); //从字符数组将数据写到文件上
}
fr.close(); //关流释放资源
fw.close();
BufferedReader
read()方法读取字符时会一次读取若干字符到缓冲区, 然后逐个返回给程序, 降低读取文件的次数, 提高效率
BufferedWriter
write()方法写出字符时会先写到缓冲区, 缓冲区写满时才会写到文件, 降低写文件的次数, 提高效率
BufferedReader br = new BufferedReader(new FileReader("aaa.txt")); //创建字符输入流对象,关联aaa.txt
BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt")); //创建字符输出流对象,关联bbb.txt
int ch;
while((ch = br.read()) != -1) { //read一次,会先将缓冲区读满,从缓冲去中一个一个的返给临时变量ch
bw.write(ch); //write一次,是将数据装到字符数组,装满后再一起写出去
}
br.close(); //关流
bw.close();
BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
BufferedReader br = new BufferedReader(new FileReader("aaa.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt"));
String line;
while((line = br.readLine()) != null) {
bw.write(line);
//bw.write("\r\n"); //只支持windows系统
bw.newLine(); //跨平台的
}
br.close();
bw.close();
使用指定的码表读写字符
InputStreamReader(字节流,编码表)
OutputStreamWriter(字节流,编码表)
//高效的用指定的编码表读
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8"));
//高效的用指定的编码表写
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("GBK.txt"), "GBK"));
int ch;
while((ch = br.read()) != -1) {
bw.write(ch);
}
br.close();
bw.close();
总结:
-
InputStream 是一个抽象类,是所有字节输入流的基类,核心方法是read();OutputStream 是一个抽象类,是所有字节输出流的基类,核心方法是write()
-
FileInputStream(文件字节流),构造器需要接受一个文件对象或者文件的路径
-
BufferedInputStream (缓冲字节流),构造器需要接受一个InputStream的子类对象,一般接受文件字节流对象。
-
PrintStream (打印流,输出流),把数据以自然语言的方式打印到文件中,构造器接受文件或者是另一个输出流
-
RandomAccessFile(随机文件读写流),既可以做输出流也可以做输入流,构造器需要接受一个文件对象或者文件的路径
-
ObjectInputStream (对象字节流),可以把对象保存成文件,构造器需要接受一个文件对象或者文件的路径
-
DataOutputStream (数据字节流),可以吧java中的基本数据类型保存成文件,构造器需要接受一个文件对象或者文件的路径