一.文件字符流
1.FileReader
读取演示
public static void main(String[] args) {
String filePath="d:\\a.txt";
int b=' ';
FileReader a=null;
try {
a=new FileReader(filePath);
while ((b=a.read())!=-1){//循环读取,使用read,单个字符读取
System.out.print((char) b);
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
a.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意这里的read返回的是int所以输出时候强转为char即可
这样的用read无参来读取
和前面的FileIpnutStream一样
效率比较低
我们用一般数组方式接收
效率高
改编版
@Test
public void Reader01(){
String filePath="d:\\a.txt";
char []q=new char[10];
int readlen=0;
FileReader a=null;
try {
a=new FileReader(filePath);
while ((readlen=a.read(q))!=-1){//循环读取,使用read,返回实际读取到的字符数
System.out.print(new String(q,0,readlen));
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
a.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
可以发现哦
就是用数组接收
都要考虑实际接收的长度问题
以免输入比原来多的字符
用一个int
readLen来限制对应操作数组长度
效果
2.FileWriter
注意
一定要close或者flush
否则是写入不到的
close或者flush方法里的一个方法
就这个方法
里面的writeBytes()
才是真正将数据写入文件的代码
任务
代码
@Test
public void s(){
FileWriter d=null;
try {
d=new FileWriter("d:\\note.txt");
d.write("风雨之后,定见彩虹");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
d.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果图
当然write还有多种形参
巧妙运用
可以传char数组
或者单个字符
还可以(String a,int off,int len)
选取字符串的一部分
数据量大的情况下,使用循环操作
二.节点流和处理流
节点流,直接操作数据源,只能对对应的数据源进行操作,有一定的限制,灵活性不够,这样的流效率可能不是很高,功能可能不是很强大
处理流,对节点流进行一个包装,比节点流功能更强大
注意一般处理流里面不会再包一个处理流,而是一个节点流,前面那样做没有意义
最后都是要回到节点流的
这个Reader或者Writer属性可以包含别的比如FileReader,CharArrayReader,FileWriter,CharArrayWriter什么的对对应的数据类型或者文件进行操作。
可以直接把其他的节点流丢进去,这种模式叫修饰器模式
类似于这种一个处理流能干多个功能
二.处理流
BufferdReader和BufferedWriter
都是字符流(因为都是Reader的子类喽)
并且关闭的时候只关闭外层流即可,底层会自动关闭包装的节点流
1.BufferdReader
演示代码
正常read是一个字符一个字符读取的
readLine会一行一行读取然后返回
用line接收效率比较高
效果图
2.BufferedWriter
任务
使用BufferWriter将
“我身无拘,武道无穷”
传入d盘的a.txt文件中(覆盖式)
@Test
public void jie(){
BufferedWriter bufferedWriter=null;
try {
bufferedWriter = new BufferedWriter(new FileWriter("d:\\a.txt"));
bufferedWriter.write("我身无拘,武道无穷");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行效果
3.Buffered字符流拷贝
任务
把d盘的作业文件夹下的ccle.docx转移到c盘以ccle01.docx命名
这是d盘作业下的ccle文件
@Test
public void copy(){
try {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("d:\\ccle01.docx"));
BufferedReader bufferedReader = new BufferedReader(new FileReader("d:\\作业\\ccle.docx"));
String line=" ";
//说明readLine只读取一行的内容没有带换行,当没有可以读取的时候返回null
while ((line=bufferedReader.readLine())!=null){
bufferedWriter.write(line);//每读取一行就写入
bufferedWriter.newLine();//插入换行符
}
System.out.println("拷贝完毕");
bufferedReader.close();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
小插曲
兄弟们
可以看出来是有一点小失败的
具体原因应该是docx文件和字符流不太匹配的原因导致的
搜过了xdm
docx属于二进制文件所以会出现以上问题
我们换一种纯文本文件
把d:\作业\ccle02.txt
弄到d:\ccle03.txt
@Test
public void copy(){
try {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("d:\\ccle03.txt"));
BufferedReader bufferedReader = new BufferedReader(new FileReader("d:\\作业\\ccle02.txt"));
String line=" ";
//说明readLine只读取一行的内容没有带换行,当没有可以读取的时候返回null
while ((line=bufferedReader.readLine())!=null){
bufferedWriter.write(line);//每读取一行就写入
bufferedWriter.newLine();//插入换行符
}
System.out.println("拷贝完毕");
bufferedReader.close();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
效果图
哈哈哈哈哈成功了xdm
注意
字符流用于纯文本文件(也称ASCLL文件)
字节流用于二进制文件
4.BufferInputStream
类似于BufferedReader,属于包装流
这个类里面包含一个InputStream,来处理各种二进制文件或者数组什么的节点流
5.BufferOutputStream
类似于BufferedWriter,属于包装流
这个类里面包含一个OutputStream,来处理各种二进制文件或者数组什么的节点流
6.二进制处理流拷贝
任务d盘作业文件夹下的文件ccle.docx
转到d盘并且重命名为ccle01.docx
ccle文件
代码
@Test
public void copy(){
byte [] a=new byte[1024];
try {
int readlen=0;
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("d:\\作业\\ccle.docx"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("d:\\ccle01.docx"));
while ((readlen=bufferedInputStream.read(a))!=-1){
bufferedOutputStream.write(a,0,readlen);
}
bufferedInputStream.close();
bufferedOutputStream.close();
System.out.println("拷贝完毕");
} catch (IOException e) {
e.printStackTrace();
}
}
效果图
对象处理流
以前我们只保存一个值
现在我们还要保存它的数据类型
上面的知识简单保存值
下面的成为序列化保存
但是序列化和反序列化是有条件的哦
上图有
推荐大家实现Serializable因为里面没有任何方法是一个标记接口
也是接受对应的OutputStream
和对应的InputStream
1.ObjectOutputStream
存储数据代码演示
package com.hansp.Reader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
@SuppressWarnings({"all"})
public class Object {
public static void main(String[] args) {
String filePath="d:\\data.txt";//这个后缀是随意的,序列化后保存的文件格式不是txt而是按照它的格式来保存的
//所以其实随便起一个后缀名就行了
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到e:\data.txt
//没有的话会先创建
objectOutputStream.writeInt(100); //int自动装箱为Integer实现了Serializable接口
objectOutputStream.writeBoolean(true);//同
objectOutputStream.writeChar('c');//同
objectOutputStream.writeUTF("ccle");//同
//下面我们自建个类Dog,保存进去
objectOutputStream.writeObject(new Dog("666",18));
objectOutputStream.close();
System.out.println("数据保存完毕");
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
效果展示
有点蒙蔽
我吧文件名后缀改成dat
然后用记事本打开一样
出现这种情况的原因
他压根不是纯文本文件你用记事本打开
当然是乱码形式或者说你看不懂的形式
但是从文本上我们依然可以看出
它是以
数据+数据类型保存的
而不是单单保存值
比如里面的Dog
那么这个创建出来的文件有什么用呢?
这就要看我们的反序列化,进行恢复
2.ObjectInputStream
代码
package com.hansp.Reader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
@SuppressWarnings({"all"})
public class ObjectInput {
public static void main(String[] args) throws ClassNotFoundException {
//先指定反序列化文件
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("d:\\data.dat"));
//读取(反序列化)的顺序需要和你序列化的顺序一直,就是write的顺序和read的顺序对应的数据要相同,不然会出事
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
System.out.println(objectInputStream.readUTF());
//System.out.println(objectInputStream.readObject());//底层会把Object转为Dog会抛一个异常
Object dog=objectInputStream.readObject();
System.out.println("dog的运行类型"+dog.getClass());
System.out.println(dog);
objectInputStream.close();//关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
效果图
注意
一般我们需要把Dog类和这个Input在同一个包下面
因为我们dog对象
编译类型是Object
需要向下转型才能调用Dog类的独有方法
此时没有Dog类就转型不了
所以需要得到Dog类来进行向下转型
如果说这个类是public的也可以直接引用(import)过来
解决方式1.同一个包下创建2.public (公有化)Dog类然后引入
3.对象处理流使用细节
3.
4.
static和transient属性会自动填null,如图
5.如图里面Master类也要序列化,继承Ser接口
标准输入输出流
System.in
这个代表标准输入键盘
new Scanner(System.in)
System.in
当你调用对应Scanner对象的next()
方法就会从System.in(键盘)来读取数据
System.out
转换流
针对纯文本文件的编码格式不同产生的一种流
注意:转换流本身就是一种字符流,接受字节流,转换成InputStreanReader这样的字符流
转换流
就是把一种字节流转成字符流
来处理文件乱码问题
这里如果文件是UTF-8编码
的话可以正常读取
如图
但是如果把编码格式转为ANSI码(国标码由系统决定对应具体的码)
别的编码格式比如ANSI格式就可能出现乱码如图
出现乱码的根本原因
没有指定读取文件的编码方式
默认UTF-8但是不能保证每个文件都是这个编码格式
所以要指定读取编码格式,以防出现乱码
但是只有字节流才能指定读取(本步骤要通过转换流指定读取编码格式),
所以要先指定字节流的读取编码格式
然后用转换流将它转换为字符流,读取纯文本文件
1.InputStreamReader
第三类构造方法
相当于不但把一个字节流转换为字符流,还能指定用读取什么编码格式
任务
代码
这里用"gbk"因为a.txt就是gbk编码格式
这里属于是先把字节流转成字符流
然后把字符流放入包装流里进行读取
效果展示
2.OutputStreamWriter
这个是按照对应的编码格式写入文件应用的
任务
代码
打印流
打印流只有输出流,没有输入流
PrintStream
继承图
构造器
代码
可以输出输出到显示器上(System.out)就是一个PrintStream,代表显示器
print方法底层其实是调用的write方法
所以第一种和第二种打印出来效果是相同的
还有一种用途
修改sout的默认位置,默认是到显示器上的,可以通过setOut来重新
更改输出位置,可以到文件中,然后直接输出就行
没有的话会新建文件进行输出
PrintWriter
构造器
可以输出到显示器上(System.out代表显示器)
可以更改路径到文件中
需要close才可以成功输进去
Properties类
任务
传统方式
建一个properties文件
读取里面的信息
代码
效果图
可以看出传统的方法本身不难,但是
如果ip,user,pwd有很多
我们用这种方法,还需要填写数据
而且当我们想指定获取某个值的时候要遍历整个文件进行判断,比较麻烦
比较麻烦这时就引出我们的pro类喽
properties类
1.读取文件
代码
效果
2.修改文件
如果没有,就添加一个文件
代码
效果
null对应的是一个注释
把null换成"hello world"的效果图
修改对应的k-v对
如果setProperty(key,value)
如果key是不存在的它就是创建,如果存在它就是修改
修改pwd为888888
效果图
底层替换机制也是HashTable