1、 流
1.1概念
内存与存储设备之间传输的通道。
1.2 流的分类
1.2.1 按方向
输入流:将<存储设备>中的内容读入到<内存>中。
输出流:将<内存>中的内容写入到<存储设备>中。
1.2.2 按单位
字节流:以字节为单位,可以读写所有数据 。
字符流:以字符为单位,只能读写文本数据 。
1.2.3 按功能
节点流:具有实际传输数据的读写功能。
过滤流:在节点流的基础之上增强功能。
2字节流
2.1字节抽象类
InputStream:字节输入流
public int read(){}。
.public int read(byte[] b){}。
public int read(byte[] b,int off,int len){}。
OutputStream:字节输出流
public void write(int n){}。
public void write(byte[] b){}。
public void write(byte[] b,int off,int len){}。
2.2 字节节点流
因为字节流无法实例化对象,所以一般声明指向子类对象,最常用的子类对象则是文件字节流(FileOutputStream、FileInputStream)
案例演示:FileInputStream读取文件
public class TestFileInputStream {
public static void main(String[] args) throws Exception{
//1创建FileInputStream,并指定文件路径
FileInputStream fis=new FileInputStream("d:\\aaa.txt");
//2读取文件
fis.read() ;
//2.1单个字节读取
int data=0;
while((data=fis.read())!=-1) {
System.out.print((char)data);
}
//2.2一次读取多个字节
byte[] buf=new byte[1024];
int count=0;
while((count=fis.read(buf))!=-1) {
System.out.println(new String(buf,0,count)); }
//3关闭
fis.close();
System.out.println("执行完毕"); } }
案例演示:FileOutputStream写入文件。
public class TestFileOutputStream {
public static void main(String[] args) throws Exception{
//1创建文件字节输出流对象
FileOutputStream fos=new
FileOutputStream("d:\\bbb.txt",true);
//2写入文件
fos.write(97);
fos.write('b');
fos.write('c');
String string="helloworld";
fos.write(string.getBytes());
//3关闭
fos.close();
System.out.println("执行完毕"); } }
2.3 字节缓冲流
缓冲流:BufferedOutputStream/BufferedInputStream
提高IO效率,减少访问磁盘的次数。
数据存储在缓冲区中,flush是将缓存区的内容写入文件中,也可以直接close。
主意缓冲流都是建立在流上的,在创建缓冲流之前还要创建字节流。字节缓冲流和字节流在现阶段学习好像看到区别。
3、字符编码
4、字符流
4.1字符抽象流
Reader:字符输入流
public int read(){}。
public int read(char[] c){}。
public int read(char[] b,int off,int len){}。
Writer:字符输出流
public void write(int n){}。
public void write(String str){}。
public void write(char[] c){}。
同样,字符流一般也是声明变量指向子类对象文件输入输出流便是其中一个重要的子类。
FileWriter:
public void write(String b) 。
一次写多个字符,将b数组中所有字符,写入输出流。
FileReader:
public int read(char[] c) 。
从流中读取多个字符,将读到内容存入c数组,返回实际读到的字符数;如果达到文件的尾
部,则返回-1。
案例演示:
public class TestFileReader {
public static void main(String[] args) throws Exception{
//1创建FileReader 文件字符输入流
FileReader fr=new FileReader("d:\\hello.txt");
//2读取
//2.1单个字符读取
int data=0;
while((data=fr.read())!=-1) {
//读取一个字符 //
System.out.print((char)data);}
char[] buf=new char[1024];
int count=0;
while((count=fr.read(buf))!=-1) {
System.out.println(new String(buf, 0, count)); }
//3关闭
fr.close(); } }
//写入
public class TestFileWriter {
public static void main(String[] args) throws Exception {
//1创建FileWriter对象
FileWriter fw=new FileWriter("d:\\write.txt");
//2写入
for(int i=0;i<10;i++) {
fw.write("java是世界上最好的语言\r\n");
fw.flush(); }
//3关闭
fw.close();
System.out.println("执行完毕"); } }
4.3 字符缓冲流
字符缓冲流相比于字节缓冲流,这个流在读写的时候能做到一次读取一行(readLine());并且支持换行符。
演示
BufferedReader br=new BufferedReader(new FileReader("D:\\write.txt"));
//读取一行
String str=br.readLine();
//读取全文
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
}
//获取全文
String line=null;
String neirong=null;
while((line=br.readLine())!=null){
neirong+=line;
neirong+="\n";
}//其中的换行符就没了,要单独添加
5、对象流
对象流同样也是一个缓冲流,它是基于字节的缓冲流,所以需要建立在字节流上,对象流是一个非常好的用来保存数据的手段,java中如果有很多相同的类型的数据,我们就能把它们集合起来作为一个对象,然后通过对象流一并保存到文件中,之后又通过对象流从文件中完整的取出一个个数据。
具体做法以及遇到过的问题如下
示例1 创建一个学生对象并写入文件中再从文件中把对象给读出来并输出。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectStream {
public static void main(String[] args) {
// 声明文件字节输出流
FileOutputStream fos = null;
// 声明对象输出流
ObjectOutputStream oos = null;
// 声明文件字节输入流
FileInputStream fis = null;
// 声明对象输入流
ObjectInputStream ois = null;
try {
// 创建对象输出流(将数据写入文件中)
// 对象输出流建立在字节流上,所以还要创建字节流(这里创建文件输出的字节流
fos = new FileOutputStream("F:/openfile/com/xitong1.txt");//在此处创建文件输出流时,文件里的内容就会被改动,可能是被空值覆盖也可能被其他值替代。如果想要文件内容不被覆盖,可以在路径后面加一个元素true(如:FileOutputStream("F:/openfile/com/xitong1.txt",true)),使得文件在写入的时候不是覆盖,而是在末尾追加。
// 基于文件字节流创建对象输出流
oos = new ObjectOutputStream(fos);//
// 这时创建一个对象,比如学生对象(学生对象四个属性,姓名、年龄、学号和分数)
Student student = new Student("kaiven", "男", 100, "171717");
// 然后利用对象输出流把学生对象存入文件中
oos.writeObject(student);
// 到此完成了一个对象的存入。
// 把对象从文件中取出
// 创建文件输入流
fis = new FileInputStream("F:/openfile/com/xitong1.txt");
// 创建对象输入流
ois = new ObjectInputStream(fis);
//这个读写有个大问题,当文件中没有对象,或者说没有数据的时候就会报异常,所以在使用对象流的时候一定要先写入再读。
// 创建学生对象把从文件中读取到的对象接收
Student student1 = (Student) ois.readObject();// 因为读取到的对象默认为Object对象,所以需要强转为student如果存入在文件中的对象不是student类那么强转就会报异常。
System.out.println(student1);// 不出意外能正常输出上面创建的学生对象。
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
//在最后时应该把这些使用过的流都关闭
ois.close();
fis.close();
oos.close();
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
保存在文件中的数据为机器码文字。如下图
对象流需注意的细节
对象序列化的细节:
必须实现Serializable接口。
必须保证其所有属性均可序列化。
transient修饰为临时属性,不参与序列化。
读取到文件尾部的标志:java.io.EOFException。
实例2 很明显使用文件保存对象时不可能只保留一个对象,或者读取一个对象。于是我想到了存储两三次,并且再读的时候也同样多次数,但这么做的话由什么来计数呢?记录存储了几次,并且下次打开的时候能获取这个记录?这里采用集合写入与读出
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ObjectStream {
public static void main(String[] args) {
// 声明文件字节输出流
FileOutputStream fos = null;
// 声明对象输出流
ObjectOutputStream oos = null;
// 声明文件字节输入流
FileInputStream fis = null;
// 声明对象输入流
ObjectInputStream ois = null;
try {
// 创建对象输出流(将数据写入文件中)
// 对象输出流建立在字节流上,所以还要创建字节流(这里创建文件输出的字节流
fos = new FileOutputStream("F:/openfile/com/xitong1.txt");
// 基于文件字节流创建对象输出流
oos = new ObjectOutputStream(fos);
// 这时创建一个对象,比如学生对象(学生对象四个属性,姓名、年龄、学号和分数)
Student student = new Student("kaiven", "男", 100, "171717");
// 然后利用对象输出流把学生对象存入文件中
//创建学生类型的集合
List<Student> list=new ArrayList<Student>();
//将学生对象添加到集合中
list.add(student);
list.add(student);
// oos.writeObject(student);
// oos.writeObject(student);
//对象输出流一次将集合写入到文件中
oos.writeObject(list);
// oos.flush();//这句话有个困惑,当我在写系统的时候没用上这句话系统就一直报错,但当我做笔记的时候再测试发现又可以忽略,不知该如何是好。
// 到此完成了一个对象的存入。
// 把对象从文件中取出
// 创建文件输入流
fis = new FileInputStream("F:/openfile/com/xitong1.txt");
// 创建对象输入流
ois = new ObjectInputStream(fis);
// 创建学生对象把从文件中读取到的对象接收
// Student student1 = (Student) ois.readObject();// 因为读取到的对象默认为Object对象,所以需要强转为student如果存入在文件中的对象不是student类那么强转就会报异常。
// Student student2 = (Student) ois.readObject();
// Student student3 = (Student) ois.readObject();
// System.out.println(student1);// 不出意外能正常输出上面创建的学生对象。
// System.out.println(student2);
// System.out.println(student3);
List<Student> list1=new ArrayList<Student>();
//将文件中的对象以集合的形式一次读出,如果这时改用Student变量去存储就会报异常,所以用什么方式存储,就只能用什么方式读出。
list1=(List<Student>) ois.readObject();
System.out.println(list);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
// 在最后时应该把这些使用过的流都关闭
ois.close();
fis.close();
oos.close();
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
6、打印流
PrintWriter:
封装了print() / println()方法,支持写入后换行。
支持数据原样打印。
案例演示:
public class TestPrintWriter {
public static void main(String[] args) throws Exception {
//1创建打印流
PrintWriter pw=new PrintWriter("d:\\print.txt");
//2打印
pw.println(97);
pw.println(true);
pw.println(3.14);
pw.println('a'); //3关闭
pw.close();
System.out.println("执行完毕"); } }
不知有何意义
7、转换流
转换流:InputStreamReader/OutputStreamWriter
可将字节流转换为字符流。
可设置字符的编码方式
案例演示
public class TestInputStreamReader {
public static void main(String[] args) throws Exception {
//1创建InputStreamReader对象
FileInputStream fis=new FileInputStream("d:\\write.txt");
InputStreamReader isr=new InputStreamReader(fis, "gbk");
//2读取文件
int data=0;
while((data=isr.read())!=-1) {
System.out.print((char)data); }
//3关闭
isr.close(); } }
public class TestOutputStreamWriter {
public static void main(String[] args) throws Exception{
//1创建OutputStreamWriter
FileOutputStream fos=new FileOutputStream("d:\\info.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos, "utf-8");
//2写入
for(int i=0;i<10;i++) {
osw.write("我爱北京,我爱故乡\r\n"); osw.flush(); }
//3关闭
osw.close();
System.out.println("执行成功"); } }
使用过的场景,可以使用于socket套接字的服务器与客户端的交互中。
8、Properties实现流的操作
Properties:属性集合。
特点:
存储属性名和属性值。
属性名和属性值都是字符串类型。
没有泛型。
和流有关。
案例演示:Properties实现流的操作。
public class TestProperties {
public static void main(String[] args) throws Exception {
//1创建集合
Properties properties=new Properties();
//2添加数据
properties.setProperty("username", "zhangsan");
properties.setProperty("age", "20");
System.out.println(properties.toString());
Set<String> pronames=properties.stringPropertyNames(); for (String pro : pronames) { System.out.println(pro+"====="+properties.getProperty(pro)); }
//4和流有关的方法
//----------1、list方法---------
PrintWriter pw=new PrintWriter("d:\\print.txt"); properties.list(pw);
pw.close();
//----------2、store方法 保存-----------
FileOutputStream fos=new FileOutputStream("d:\\store.properties");
//与setProperty配合使用,setProperty把要存入的数据写进properties中,然后store把数据再写入到properties文件中,这种文件也被叫做配置文件
properties.store(fos, "注释");
fos.close();
//----------3、load方法 加载-------------
Properties properties2=new Properties();
FileInputStream fis=new FileInputStream("d:\\store.properties");
properties2.load(fis);
fis.close();
System.out.println(properties2.toString()); } }