IO流体系
4.1 IO流分类:
I:Input:输入
O:output:输出
按照流向分:
输入流:InputStream
输出流:OutputStream
输入流:读数据
输出流:写数据
参数物:内存和硬盘
按照读写单位分:字节流、字符流
Java中流还可以分为:
节点流:节点流又称为低级流,是实际连接程序与数据源的"管道",负责传输数据.读写一定是建立在节点流上进行的.
处理流:处理流又称为高级流,用于处理其他流,不能独立存在(没有意义),使用高级流处理其他流的目的是通过高级流带
来的功能简化我们对数据读写时的某些复杂处理.
4.2 字节流
抽象基类:
InputStream:字节输入流
- FileInputStream
OutPutStream:字节输出流
- FileOutputStream
4.2.1 文件流:
是一对低级流(节点流)
FOS:字节输出流,用于写数据
构造方法:
FileOutputStream(File file):
FileOutputStream(String filename):
写数据方法:
Wirte(byte[] bys)
FOS写数据的步骤:
1. 创建Fos对象
2. 调用write方法写数据
3. 释放资源
注意点:
输出流对象做的事情:
1. 如果目标文件不存在,创建目标文件
2. 创建输出流对象
/**
* FileOutputStream向文件中写数据
* @author adminitartor
*
*/
public class FosDemo {
public static void main(String[] args) throws IOException {
//创建文件对象
// File file = new File("fos.txt");
// file.createNewFile();
//向文件中写数据
//1.创建输出流对象
FileOutputStream fos = new
FileOutputStream("fos1.txt");
//2.写数据
fos.write("hello,文件字节输出流!".getBytes());
//3.释放资源
fos.close();
}
}
思考:如何向文件中追加写入数据?
调用另外一个构造方法
-FileOutputStream(File/String,boolean append)
/*
* 实现追加功能创建输出流对象
* FileOutputStream(File,boolean)
*/
FileOutputStream fos = new
FileOutputStream("fos1.txt", true);
//2.写数据
fos.write("hello!".getBytes());
//3.释放资源
fos.close();
FIS:字节输入流
构造方法:
FileInputStream(File file)
FileInputStream(String name)
读取数据:
按单个字节读取 - read()
按字节数组读取 - read(byte[]) - int
按照单个字节读取和按照字节数组读取数据的用法:
通常用于复制
案例:复制文件
1. 单个字节复制
2. 字节数组复制
注意点:
1.字节流可以操作所有类型的文件
文件类型:文本文件,图片文件,音频文件,视频文件
2.复制文件时,两个文件的类型必须是兼容的
<1> 原文件:xx.jpg
<2> 复制的文件:xx.png
按照单个字节复制文本文件
public static void main(String[] args) throws IOException {
/*
* 按照单个字节复制
* 思路:
* 1.创建输入流对象,输出流对象
* 2.循环读取和循环写数据
* 3.释放资源
*/
FileInputStream fis =
new FileInputStream("FisDemo.java");
FileOutputStream fos =
new FileOutputStream("copy.java");
//复制 : 先读后写
int ch = -1;
while((ch=fis.read())!=-1){
fos.write(ch);
}
fos.close();
fis.close();
}
按照字节数组复制图片
public static void main(String[] args) throws IOException {
/*
*按照字节数组复制
*步骤:
* 1.创建输入流,输出流对象
* 2.完成复制
* 3.释放资源
*/
FileInputStream fis = new
FileInputStream("33.jpg");
//复制的文件和原文件必须是兼容的
FileOutputStream fos = new
FileOutputStream("copy3.txt");
//复制 - 按照字节数组
byte[] bys = new byte[1024*10];
int len = 0;
/*
* 注意点:先读后写
* 遵循规则:怎么读的就怎么写
*/
while((len = fis.read(bys))>0){
fos.write(bys, 0, len);
}
//释放资源
fos.close();
fis.close();
作业:
1. 用户从控制台进行注册用户,输入用户名和密码,可以注册多个用户信息,将用户信息保存到集合中,当用户选择不再继续时,将集合中的所有用户信息写入文件。
2. 完成文本,图片,音频,视频的复制(每种复制2种方式,按照单个字节复制,按照字节数组复制)
a) 注意点:复制较大文件时注意字节复制和字节数组复制的时间
b) 输出当前时间的毫秒表示
<1> System.currentTimeMills(); - long
2.IO流
2.1.1 缓冲流
字节流:
文件流
缓冲流
是一对处理流(高级流)
BufferedOutputStream: 字节缓冲输出流
BufferedInputStream:字节缓冲输入流
BOS:BufferedOutputStream工作原理
在向硬件设备做写出操作时,增大写出次数无疑会降低写出效率,为此我们可以使用缓冲输出流来一次性批量写出若干数据减少写出次数来提高写出效率。
BufferedOutputStream缓冲输出流内部维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。
构造 方法:
BufferedOutputStream(OutputStream os)
方法:
write(int b)
write(byte[] bys)
write(byte[] bys, int offset,int len)
案例:
用字节缓冲输出流写数据
/**
* 用字节缓冲输出流写数据
* @author adminitartor
*
*/
public class BosDemo {
public static void main(String[] args) throws IOException {
/*
* 步骤:
* 1.创建流对象
* 2.写数据
* 3.释放资源
*/
BufferedOutputStream bos = new
BufferedOutputStream(
new FileOutputStream("bos.txt"));
bos.write("hello,字节缓冲输出流!".getBytes());
bos.close();
}
}
BIS:BufferedInputStream工作原理
在读取数据时若以字节为单位读取数据,会导致读取次数过于频繁从而大大的降低读取效率。为此我们可以通过提高一次读取的字节数量减少读写次数来提高读取的效率。
BufferedInputStream是缓冲字节输入流。其内部维护着一个缓冲区(字节数组),使用该流在读取一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据被全部读取完毕,会再次读取若干字节从而反复。这样就减少了读取的次数,从而提高了读取效率。
构造方法
BufferedInputStream(InputStream is)
方法:
read() - int
read(byte[] bys) - int
案例:按照字节数组读取数据
/*
* 读取数据的步骤:
* 1.创建流对象
* 2.读取数据
* 3.释放资源
*/
BufferedInputStream bis = new
BufferedInputStream(
new FileInputStream("bos.txt"));
//读取数据并打印到控制台
byte[] bys = new byte[1024];
int len = 0;
while((len=bis.read(bys))>0){
//将byte[]中的数据转换成String
System.out.print(new String(bys, 0, len));
}
bis.close();
}
练习:复制图片,分别用字节节点流和字节缓冲流复制,比较二者的效率。
缓冲流操作数据,数据保存在缓冲区中,将来从缓冲区中读出数据时,需要刷出缓存
.close()作用:在关闭流之前,先进行缓存区的刷出操作
flush方法: 清空缓冲区,将缓冲区中的数据强制写出。
是输出流中的方法。
缓冲流复制图片,如果不关闭出现数据丢失,
解决办法 - flush()
BufferedInputStream bis = new
BufferedInputStream(
new FileInputStream("33.jpg"));
BufferedOutputStream bos = new
BufferedOutputStream(
new FileOutputStream("bos.jpg"));
System.out.println(System.currentTimeMillis());
byte[] bys = new byte[1024];
int len = 0;
while((len=bis.read(bys))>0){
bos.write(bys, 0, len);
bos.flush();
}
System.out.println(System.currentTimeMillis());
// bos.close();
// bis.close();
//流不关闭,有可能出现数据丢失现象
思考:
是否可以向某文件(已经有数据)中的某个指定位置插入指定数据?
FileOutputStream(File,boolean)
3.RandomAccessFile文件操作
随机访问流
此类并不是真正的流
Java提供了一个可以对文件随机访问的操作,访问包括读和写操作。该类名为RandomAccessFile。该类的读写是基于指针的操作。
创建对象
• RandomAccessFile在对文件进行随机访问操作时有两个模式,分别为只读模式(只读取文件数据),和读写模式(对文件数据进行读写)。
• 构造方法:
• RandomAccessFile(File file,String mode)
• RandomAccessFile(String filename,String mode)
mode: r rw rws rwd
操作:
读写操作:
写数据:
write(int b)
wirte(byte[] bys)
write(byte[] by,int offset,int len)
读数据:
read() – int
read(byte[] b) - int
注意点:怎么写的就怎么读
eg:
writeBoolean(true)
writeChar('a')
writeInt(2)
readBoolean();
readChar()
readInt()
close() :
RandomAccessFile在对文件访问的操作全部结束后,要调用close()方法来释放与其关联的所有系统资源。
案例:向空文件中写入数据,将数据读取出来打印到控制台
注意点:不论通过此对象进行读好像写的操作,指针都会随之移动,如果向移动指针,需要调用raf.seek(long pos)
文件指针操作
getFilePointer() - long - 获取当前文件中的指针偏移量
seek(long pos) - void - 将指针移动到指定位置(指定偏移量)
/*
* 向文件中写入数据,之后读取出来打印到控制台
* 步骤:
* 1.创建对象
* 2.读写操作
* 3.释放资源
*/
File file = new File("random.txt");
RandomAccessFile raf = new
RandomAccessFile(file,"rw");
System.out.println(raf.getFilePointer());
//写操作
raf.write("hello,随机访问流对象!".getBytes());
System.out.println(file.length());
System.out.println(raf.getFilePointer());
raf.seek(0);
//读取操作
byte[] bys = new byte[1024];
int len = 0;
while((len=raf.read(bys))>0){
System.out.print(new String(bys,0,len));
}
raf.close();
}
临时文件的创建方式:
//创建临时文件
File tmpFile = File.createTempFile("test",".tmp");
System.out.println(tmpFile.getAbsolutePath());
tmpFile.deleteOnExit();
练习:向一个已有数据的文件内部中间位置插入数据。
File:a.txt : hello,world
操作:在hello后面插入tom
结果:a.txt:hellotom,world
/**
* 向一个已有数据的文件内部中间位置插入数据。
File:randomAccess.txt : hello,world
操作:在hello后面插入tom
结果:randomAccess.txt:hellotom,world
注意点:原来后面位置的内容需要后移
1.先将hello后的数据读取出来复制到一个临时文件中
2.向hello后插入要添加的数据 - tom
3.读取临时文件中的数据写到tom的后面
* @author adminitartor
*
*/
public class InsertDemo {
public static void main(String[] args) throws IOException {
//创建RandomAccessFile对象
RandomAccessFile raf = new RandomAccessFile("randomAccess.txt", "rw");
File tmpFile = File.createTempFile("random", ".tmp");
RandomAccessFile raftmp = new RandomAccessFile(tmpFile, "rw");
//先将指针偏移量移动
raf.seek(5);
//复制之后的内容到临时文件中去
byte[] bys = new byte[1024];
int len = 0;
while((len=raf.read(bys))>0){
//写入到临时文件中去
raftmp.write(bys, 0, len);
}
System.out.println(tmpFile.getAbsolutePath());
//插入数据操作
raf.seek(5);
raf.write("tom".getBytes());
//读取临时文件中的数据,将其写入此时文件tom的后面
len = 0;
raftmp.seek(0);
while((len=raftmp.read(bys))>0){
//写入目标文件
raf.write(bys, 0, len);
}
//删除临时文件
tmpFile.deleteOnExit();
raf.close();
raftmp.close();
}
}
升级版练习:已存在两个文件,xx.java xxxx.java
1. 将第二个文件的数据插入到第一个文件的某个位置
2. 将第二个文件的数据拼接到第一个文件的结尾
思考:
是否可以向文件中写入一个对象?
3.1.对象流
读写对象的流:
ObjectOutputStream
ObjectInputStream
ObjectOutputStream:
构造方法:
ObjectOutputStream(OutputStream os)
方法:
writeObject(Object)
对象是存在于内存中的。有时候我们需要将对象保存到硬盘上,又有时我们需要将对象传输到另一台计算机上等等这样的操作。这时我们需要将对象转换为一个字节序列,而这个过程就称为对象序列化。相反,我们有这样一个字节序列需要将其转换为对应的对象,这个过程就称为对象的反序列化。
对象的序列化:对象 -- >字节序列
对象的反序列化:字节序列 -- >对象
想要一个对象是可序列化的,实现过程:
对象所属的类实现接口:Serializable接口
该接口中没有任何内容,此接口是一个标志接口,用于表名某个类的对象是可序列化的。
Serializable接口:
ObjectOutputStream在对对象进行序列化时有一个要求,就是需要序列化的对象所属的类必须实现Serializable接口。
实现该接口不需要重写任何方法。其只是作为可序列化的标志。
public class Person implements Serializable {
private int id;
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 [id=" + id + ", name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (id != other.id)
return false;
return true;
}
}
/**
* 向文件中写入对象数据
* @author adminitartor
*
*/
public class WriteObjectDemo {
public static void main(String[] args) throws FileNotFoundException, IOException {
//将Person对象写入文件
//创建对象输出流对象
ObjectOutputStream oos = new
ObjectOutputStream(
new FileOutputStream("oos.txt"));
Person obj = new Person(1, "tom", 12);
//写的操作
oos.writeObject(obj);
//释放资源
oos.close();
}
}
对象的序列化 : 对象 -->字节序列
应用场景:
` 1.将对象持久化到磁盘
2.将对象用于网络传输
对象的反序列化:字节序列还原成对象
案例:
读取文件中的对象信息将其还原成对象并将对象信息打印出。
ObjectInputStream:
构造方法
ObjectInputStream(InputStream is)
方法
readObject() - Object
/**
* 读取文件中的对象信息并还原成对象
* @author adminitartor
*
*/
public class ReadObjectDdmeo {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//创建对象
ObjectInputStream ois = new
ObjectInputStream(
new FileInputStream("oos.txt"));
//读取对象
Person person = (Person)ois.readObject();
System.out.println(person);
//释放资源
ois.close();
}
}
如果对一个类添加属性或减少属性,对已经写好的对象进行反序列化,出现什么问题?如何解决?
SeriaVersionID:
通常实现该接口的类需要提供一个常量serialVersionUID,表明该类的版本
如果声明的类的对象序列化存到硬盘上面,之后随着需求的变化更改了类的属性(增加或减少或改名),那么当反序列化时,就会出现InvalidClassException,这样就会造成不兼容性的问题。
序列化和反序列化的机制:
当一个类实现了Serializable接口后,编译器会提示应当添加一个常量:serialVersionUID,这个常量标识当前类的序列化版本号.若不指定,编译器在编译当前类时会根据当前类的结构生成,但是只要类的结构发生了变化,那么版本号就会改变.版本号决定着一个对象是否可以反序列化成功.
当对象输入流在将一个对象进行反序列化时会检查该对象的版本号与当前程序中这个类的版本号是否一致
若一致:反序列化成功,若当前类发生了改变,那么还原依然存在的属性.
若不一致,则反序列化方法readObject会抛出异常.
public class Person implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5052296998194450162L;
对象所属的类手动生成版本号之后,对之前写入文件的对象进行反序列化成功!
transient关键字:
当一个属性被transient修饰后,该属性在进行对象序列化时其值会被忽略.
案例:
Person类:
int id ,
String name,
int age ,
String desc,详细描述
将Person对象进行序列化写入文件中,将关键信息写入,desc信息不写入
忽略不必要的属性值可以达到对象序列化"瘦身"的效果.
Student类
public class Student implements Serializable {
private static final long serialVersionUID = 4382717422241129832L;
private Integer id;
private String name;
private Integer age;
private transient String desc;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int id, String name, int age, String desc) {
super();
this.id = id;
this.name = name;
this.age = age;
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + ", desc=" + desc + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
return true;
}
测试类:
测试trainsient修饰的属性的值是否写入文件
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
/*
* 将Student对象信息写入文件
* 要求:desc描述信息不写入
*/
Student student = new Student(1, "tom", 23, "人很高,很瘦。。。。");
//创建对象流对象
ObjectOutputStream oos = new
ObjectOutputStream(
new FileOutputStream("student.txt"));
oos.writeObject(student);
oos.close();
//反序列化
ObjectInputStream ois = new
ObjectInputStream(
new FileInputStream("student.txt"));
Student student2 = (Student)ois.readObject();
System.out.println(student2);
ois.close();
}
注意点:
当一个对象是可序列化时,如果内部的成员是别的对象,那么,作为成员的其他对象一定也是可序列化的。
IO流:
字节流
OutputStream: - FileOutputStream
InputStream: - FileInputStream
字节缓冲流:
OutputStream:-BufferedOutputStream
InputStream :-BufferedInputStream
特殊的方法:flush()
RandomAccessFile:文件操作类
构造方法:
RandomAccessFile(File/String,String mode)
mode:r rw rws rwd
此对象可以对进行进行读写操作,此对象是基于指针的操作类对象。
方法:
getFilePointer() - long:获取当前指针的偏移量
seek(long pos):-void:移动当前指针的偏移量
临时文件:
File.createTempFile(String prefix,String suffix)
删除操作:deleteOnExit()
RandomAccessFile和临时文件配合使用,可以完成两个文件之间的插入数据操作
对象的序列化:
1.向文件中写对象数据
一组对象流:
ObjectOutputStream:-writeObject(Object)
ObjectInputStream: -readObject() - Object
2.对象如果用于持久化到磁盘,或用于网络传输,此时对象必须转换成字节序列才可以。
对象的序列化:对象 -- >字节序列
对象的反序列化:字节序列 -->对象
如何实现对象的序列化:对象所属的类实现Serialiazable接口
3. 序列版本号:决定了是否可以反序列化成功
4. transient关键字;transient:短暂的,在序列化时可以忽略
5. 如果一个对象要实现序列化,而此对象内部有另外其他的对象,此时其他对象所属的类一定也是可序列化的。
3.2 字符流(文本数据IO流)
3.2.1 Reader和Writer
Reader:字符输入流的抽象父类
Writer:字符输出流的抽象父类。
字符流是以字符(char)为单位读写数据的。一次处理一个字符。
字符流的底层仍然是基本的字节流。
字符流封装了字符的编码解码算法。
Writer:
-OutputStreamWriter : 转换流
构造方法:
OutputStreamWriter(OutputStream os)
OutputStreamWriter(OutputStream os,String csn)
csn:charsetName
常用方法:
写数据:
write(int c) :写出一个字符
write(char[] chs):将给定的字符数组中的所有字符写出
write(String str):将给定的字符串写出
write(char[] chs,int offset,int len):
将给定的字符数组中从offset处开始连续的len个字符写出
3.2.2 转换流:
Writer和Reader的子类:
OutputStreamWriter
使用该流可以设置字符集,并按照指定的字符集将字符转换为对应字节后通过该流写出。
OutputStreamWriter(OutputStream out,String charsetName)
n 基于给定的字节输出流以及字符编码创建OSW
OutputStreamWriter(OutputStream out)
n 该构造方法会根据系统默认字符集创建OSW
/**
* OutputStreamWriter字节流对象的使用
* 构造方式 - 2
* 方法 - write系列
* @author adminitartor
*
*/
public class OswDemo {
public static void main(String[] args) throws IOException {
/*
* 向osw.txt文件中写入一个字符串
*/
//创建流对象
// OutputStreamWriter osw = new
// OutputStreamWriter(
// new FileOutputStream("osw.txt"));
OutputStreamWriter osw = new
OutputStreamWriter(
new FileOutputStream("osw1.txt"), "UTF-8");
//写数据
osw.write("hello,字符流中的转换流来了!");
osw.close();
}
}
Reader:
-InputStreamReader:
使用该流可以设置字符集,并按照指定的字符集从流中按照该编码将字节数据转换为字符并读取。
构造方法:
InputStreamReader(InputStream in,String charsetName)
n 基于给定的字节输入流以及字符编码创建ISR
InputStreamReader(InputStream in)
n 该构造方法会根据系统默认字符集创建ISR
方法:
read() - int 读取单个字符
read(char[]) - int :按照字节数组读取,返回值:实际读取的字符数组中字符的长度
注意点:
1.用字符流读写数据,读和写的时候的编码解码字符集必须是一致的。否则会出现乱码。
2.字符流只能操作文本文件,不可以操作其他类型的文件
作业:完成对一个文本文件的复制(用字符流)
2 字符流(文本数据IO流)
2.1 字符缓冲流
缓冲字符流:缓冲字符流由于内部有缓冲区,读写字符的效率高.并且字符缓冲流的特点是可以按行读写字符串.
BufferedWriter
BufferedReader
PrintWriter也是缓冲字符输出流,它内部总是连接BufferedWriter.更常用.
2.1.1 PrintWriter:缓冲字符输出流
PrintWriter提供了直接对文件进行写操作的构造方法:
构造方法:8个(看API)
2大类:
1. 指向目标文件,可以认为指定字符集
2. 指向流对象,可以开启行自动刷新功能
方法:
print()
println()
/**
* PrintWriter:
* @author adminitartor
*
*/
public class PrintWriterDemo {
public static void main(String[] args) throws FileNotFoundException {
//创建流对象
PrintWriter pw = new PrintWriter("pw.txt");
//写数据
// pw.print("hello,字符缓冲输出流!");
pw.println("hello");
//释放资源
pw.close();
}
}
练习:以UTF-8的字符集编码向文件中写入字符串
PrintWriter pw = new PrintWriter("pw2.txt","utf-8");
// //写数据
// pw.println("UTF-8字符集进行编码!");
// //释放资源
// pw.close();
行自动刷新功能:
当PrintWriter的构造方法第一个参数为流(字节流,字符流均可)时,那么支持一个重载的构造方法可以传入一个boolean值,该值若为true,则当前PrintWriter具有自动行刷新功能,即:每当调用println方法写出一行字符串后会自动调用flush方法将其数据写出. 需要注意,调用print方法是不会flush的
public class AutoFlushDemo {
public static void main(String[] args) throws FileNotFoundException {
//创建pw对象
PrintWriter pw = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream("auto.txt")),true);
//写数据
pw.println("是否具有行自动刷新功能!");
}
}
创建PW对象,如果构造方法参数是Writer,也可以指定编码字符集,方式:
PrintWriter(new OutputStreamWriter(OutputStream,String csn))
2.1.2 BufferedReader:缓冲字符输入流
BufferedReader是缓冲字符输入流,其内部提供了缓冲区,可以提高读取效率。
BufferedReader的常用构造方法:
– BufferedReader(Reader reader)
BufferedReader提供了读取一行字符串的方法:
String readLine()
该方法会连续读取若干字符,直到读取了换行符为止,然后将换行符之间读取到的所有字符以一个字符串形式返回.需要注意,返回的字符串中不包含最后的换行符.当该方法返回null时,表示末尾(不会再读取到任何数据)
案例:
1. 读取某个文本文件中的所有数据并打印
2. 读取以utf-8字符集进行编码的文件中的数据并打印
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
/*
* 读取AutoFlushDemo.java文件中的所有数据并打印
* 到控制台
*/
//创建流对象
// BufferedReader br = new
// BufferedReader(
// new InputStreamReader(
// new FileInputStream(
// "AutoFlushDemo.java")));
// //读取数据
// String str = null;
// while((str=br.readLine())!=null){
// System.out.println(str);
// }
// br.close();
/*
* 用指定字符集读取文件中的数据
*/
BufferedReader br = new
BufferedReader(
new InputStreamReader(
new FileInputStream(
"pw2.txt"), "UTF-8"));
//按行读取数据
String str = null;
while((str=br.readLine())!=null){
System.out.println(str);
}
br.close();
}
}
练习:实现文件文件的复制
/**
* 将AutoFlushDemo.java文件中的内容进行复制
* @author adminitartor
*
*/
public class CopyDemo {
public static void main(String[] args) throws IOException {
//创建对象
BufferedReader br = new
BufferedReader(
new InputStreamReader(
new FileInputStream("AutoFlushDemo.java")));
PrintWriter pw = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream("copy.txt")));
//复制
String str = null;
while((str=br.readLine())!=null){
pw.println(str);
}
//释放资源
br.close();
pw.close();
}
}
字符流:
抽象基类
Writer
-OutputStreamWriter
构造方法:2个
也叫做转换流,内部完成了字符-->字节的转换过程,即内部封装了编码过程,可以人为指定字符集进行编码。通过构造方法指定。
方法:
write(String)
Reader:
- InputStreamReader:
构造方法:2个
在创建流对象时可以人为指定字符集,通过构造方法指定。
方法:
read(char[])
字符缓冲流:
BufferedReader
PrintWriter
注意点:
字符缓冲流具有特有的功能:按行读写数据
PrintWriter:
构造方法:2大类
1. 指向目标文件,可以指定字符集
2. 指向流对象,可以开始行自动刷新功能
方法:
print()
println() :带换行
行自动刷新功能:
如果对象开启此功能,在调用println()时,自动调用flush()
功能的开始:构造方法中如果第一个参数是流,那么可以开启此功能。
BufferedReader:
构造方法
BufferedReader(Reader)
方法
readLine()-String
一次读取一行数据
用字符缓冲流复制文件(文本文件)
如果现操作的是文本文件:优先选择字符流中的缓冲流
如果现操作的是非文本文件:只能选择字节流,优先选择字节流中的缓冲流
如果现对一个文件既进行读操作,也进行写操作,可以考虑选择RandomAccessFile对象。