1 file类使用
2 IO流概述
2.1 流的三种分类
- 流向 : 输入流和输出流
- 数据单位 : 字节流和字符流
- 流的角色 : 节点流和处理流
2.2 四个IO流中的抽象基类
- OutputStream 字节输出流
- Inputstream 字节输入流
- Reader 字符输入流
- Writer 字符输出流
3 文件流(节点流)
3.1 FileOutputStream
字节流操作不会用到缓存区,不需要刷新缓存,fileOutputStream.flush();但字节流操作时用到缓存(内存),一般会调用close()方法关闭时刷新缓存。
面试题:close()和flush()的区别?
A:close()关闭流对象,但是先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了。
B:flush()仅仅是刷新缓冲区(一般写字符时要用,因为字符是先进入的缓冲区),流对象还可以继续使用
构造方法
-
public FileOutputStream(File file) throws FileNotFoundException{}
若使用第一个默认以后写都是把之前的清空再写 -
public FileOutputStream(File file,boolean append) throws FileNotFoundException{}
第二个参数为true,则字节将写入文件的末尾而不是开头。
public static void main(String[] args) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream("F:\\a.txt");
String value = "你好世界";
byte[] bytes = value.getBytes();
fileOutputStream.write(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.2 FileInputStream
public static void main(String[] args) {
InputStream f = null;
int len = 0; //记录读取到的字节
try {
f = new FileInputStream("F:\\a.txt");
//int read(byte[] b):一次读取一个字节数组,输入流会把读取到的内容放入到这个字节数组中,并返回读取到的个数, 如果读取结束返回-1.
while((len = f.read()) != -1){ //从文件中读取一个字节数的数据。并返回读取到的这个字节。 如果读取结束,返回的是-1.
System.out.println((char) len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(f != null){
f.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.3 FileReader
public static void main(String[] args) {
Reader reader = null;
try {
reader = new FileReader("F:\\a.txt");
char[] str = new char[55];
int len = 0;
while((len = reader.read(str)) != -1){
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader != null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.4 FileWriter
需要注意的是构造方法中的是否追加参数,还有就是writer的write并没有将数据直接写进文件而是保存在缓冲区,flush方法才是将缓冲去的数据写入到文本。
public static void main(String[] args) {
Writer writer = null;
try {
writer = new FileWriter("F:\\a.txt",true);
writer.append("你好");
writer.write("你好你好");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(writer != null){
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4 缓冲流
目的:通过使用缓存,加快读取和写入数据的速度。
原因:内部提供了一个缓冲区,默认情况下是8192,即8kb
如果需要大量的读写,使用缓冲流效果更好
4.1 BufferedOutputStream
4.2 BufferedInputStream
4.3 BufferedWriter
4.4 BufferedReader
操作和3中类似
4.4 案例:实现图片复制
public static void main(String[] args) {
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
bufferedInputStream = new BufferedInputStream(new FileInputStream("F:\\01.jpg"));
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("F:\\02.jpg"));
byte[] bytes = new byte[1024];
int len = 0;
while((len = bufferedInputStream.read(bytes)) != -1){
bufferedOutputStream.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedInputStream != null){
try {
bufferedInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bufferedOutputStream != null){
try {
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4 转换流
转化流属于字符流
4.1 OutputStreamWriter
OutputStreamWriter 是字符流通向字节流
的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节
。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去
。
public static void main(String[] args) {
FileOutputStream fileOutputStream = null;
OutputStreamWriter outputStreamWriter = null;
try {
fileOutputStream = new FileOutputStream("F:\\a.txt");
outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");
outputStreamWriter.write("你好");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(outputStreamWriter != null){
try {
outputStreamWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.2 InputStreamReader
InputStreamReader 是字节流通向字符流
的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
public static void main(String[] args) {
FileInputStream fileInputStream = null;
//将字节转换为字符
InputStreamReader inputStreamReader = null;
try {
fileInputStream = new FileInputStream("F:\\a.txt");
inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
char[] buf = new char[20];
int len = 0;
while((len = inputStreamReader.read(buf)) != -1){
String str = new String(buf,0,len);
System.out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
5 对象流
有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。
- 序列化: 是对象转换成一个字节序列的过程,是一个写操作
- 反序列化: 一个字节序列转换成对象的过程 ,是一个读操作
- 当使用对象流写入或者读取对象的时候,必须保证该对象是序列化的
5.1 ObjectOutputStream(OutputStream out)
public static void main(String[] args) {
//序列化:将内存中的java对象读取到硬盘中或通过网络传输出去,使用ObjectOutputStream实现
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:\\object.dat"));
objectOutputStream.writeObject(new String("我爱it"));
objectOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(objectOutputStream != null){
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.2 ObjectInputStream (InputStream in)
public static void main(String[] args) {
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(new FileInputStream("F:\\object.dat"));
Object o = objectInputStream.readObject();
String str = (String) o;
System.out.println(str);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(objectInputStream != null){
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.3 自定义类实现序列化
需要满足的条件
- 实现Serializable接口
- 对象所在的类提供常量:序列版本号
public static final Long serializableID = 698515664L;
随便数字多少 - 要求对象的属性也必须是可序列化的。(基本数据类型本身是可序列化的)
- static、transient修饰的属性不能被序列化不能被ObjectOutputStream和ObjectIntputStream序列化
public class Person implements Serializable {
public static final Long serializableID = 698515664L;
private String name;
private int age;
public Person() {
}
public Person(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 +
'}';
}
}
一般情况下用JSON
6 随机存取文件流
RandomAccessFile
6.1 基础使用
public static void main(String[] args) {
//既可以作为输入流又可以作为输出流
RandomAccessFile randomAccessFile1 = null;
RandomAccessFile randomAccessFile2 = null;
try {
randomAccessFile1 = new RandomAccessFile("F:\\01.jpg","r");
randomAccessFile2 = new RandomAccessFile("F:\\02.jpg","rw");
byte[] bytes = new byte[1024];
int len = 0;
while((len = randomAccessFile1.read(bytes)) != -1){
randomAccessFile2.write(bytes,0,len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(randomAccessFile1 != null){
try {
randomAccessFile1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(randomAccessFile2 != null){
try {
randomAccessFile2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6.2 seek方法
/*
使用RandomAccessFile实现数据的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
//思考:将StringBuilder替换为ByteArrayOutputStream
}