API--基本的IO操作
一.基本的知识点
1. 输入与输出
输入:输入是一个从外界进入到程序的方向,通常我们需要“读取”外界的数据时,使用输入。所以输入是用来读取数据的。
输出:输出是一个从程序发送到外界的方向,通常我们需要”写出”数据到外界时,使用输出。所以输出是用来写出数据的。
2. 简述节点流和处理流的区别,以及Java流式输入输出的架构特点
1)按照流是否直接与特定的地方 (如磁盘、内存、设备等) 相连,分为节点流和处理流两类。节点流可以从或向一个特定的地方(节点)读写数据;处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。
2)处理流的构造方法总是以一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接
3. InputStream与OutputStream常用方法
InputStream是所有字节输入流的父类,其定义了基础的读取方法,常用的方法如下:
int read()
读取一个字节,以int形式返回,该int值的”低八位”有效,若返回值为-1则表示EOF。
int read(byte[] d)
尝试最多读取给定数组的length个字节并存入该数组,返回值为实际读取到的字节量。
OutputStream是所有字节输出流的父类,其定义了基础的写出方法,常用的方法如下:
void write(int d)
写出一个字节,写的是给定的int的”低八位”
1 void write(byte[] d)
将给定的字节数组中的所有字节全部写出
4. 任何扩展流,都不能单独使用,必须依赖于一个"节点流"
BufferedOutputStream 扩展流,必须依赖"节点流"
构造器依赖:创建扩展流对象,必须先提供接节点流
5. 扩展流的底层,就是节点流!
扩展流== 过滤流==装饰流==过滤器
6. "节点流":数据流开始的地方,是可以单独使用的基本流
7.对象输入输出流
1) 是扩展流,必须依赖与节点流
2) 扩出对象的读写功能。可以按照对象为单位进行读写
8.将对象拆分为Byte数据,进行读写
写的时候,将对象拆分为byte写到文件中。
读取时候,将文件中的byte读取合并为对象。
9.将任何数据拆分为byte称为“序列化“! 反之称为反序列化。
10. RandomAccessFile和FileInputStream及FileOutputStream在使用中的区别?
RandomAccessFile使用随机访问的方式,而FileInputStream及FileOutputStream使用的是流式访问的方式。
11. 名称解释:ISO8859-1,GBK,UTF-8
1) ISO8859-1: 西文编码就是ASCII,一个英文字母一个字节。
2)GBK:中文编码是GB2312的超集, 1-2变长编码, 英文与ASCII一致, 中文2个字节,可以对20000多个汉字进行编码。
3)UTF-8: 1到4字节的变长编码, 英文与ascII一致, 中文3个字节。
12.分别简述ISR和OSW的工作原理
InputStreamReader字符输入流。使用该流可以设置字符集,并按照指定的字符集从字节流中按照指定编码将字节数据转换为字符数据并读取。
OutputStreamReader字符输出流。使用该流可以设置字符集,并按照指定的字符集将字符转换为对应的字节后通过该流写出。
代码练习:FileOutputStream是文件的字节输出流
(1)// 创建对象(重写模式)
1 /* 2 * 以写的方式打开文件,如果文件存在,就清除文件内容, 3 * 如果文件不存在就创建文件。 4 * 如果目标是一个文件夹或只读文件,就 抛出异常! 5 */ 6 public class FOSDemo01 { 7 public static void main(String[] args) throws IOException { 8 //创建文件字节输出流 9 FileOutputStream fos= 10 new FileOutputStream("fos.txt"); 11 //写出一组字节 12 fos.write("hello".getBytes()); 13 fos.close(); 14 } 15 }
在当前工程下生成了文件fos.txt,该文件的内容为“hello “;再次运行方法,并查看文件内容,该文件的内容仍然为“hello”。
注意,若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
(2)//构建FOS对象写文件(采用追加模式),第二个参数若为true,那么通过该FOS写出的数据都是在文件末尾追加的。
1 public class FOSDemo02 { 2 public static void main(String[] args) throws IOException { 3 //构造方法 方式一:创建一个向指定对象表示的文件中写出数据的文件流 4 FileOutputStream file= 5 new FileOutputStream(new File("fos.txt"),true); 6 //方式二:创建一个向指定名称文件中写出数据的文件流, 7 8 // FileOutputStream file= 9 // new FileOutputStream("fos.txt",true); 10 file.write("hello".getBytes()); 11 file.close(); 12 } 13 }
(3)FileInputStream是文件的字节输入流
1 public class FOSDemo03 { 2 public static void main(String[] args) throws IOException { 3 FileInputStream fos= 4 new FileInputStream("fos.txt"); 5 int d=-1; 6 //这是模式化写法,是”经典“写法! 7 // int read() 读取一个byte, 该方法返回-1时表示读取到了文件末尾; 8 //int read(byte[] buf) 读取一批byte 9 while((d=fos.read())!=-1){ 10 System.out.println((char)d+" "); 11 } 12 fos.close(); 13 } 14 }
(4)//实现文件复制(单个操作字节数目)
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 public class FOSDemo04 { 6 public static void main(String[] args) throws IOException { 7 //打开输入文件,原始文件 8 FileInputStream fos= 9 new FileInputStream("fos.txt"); 10 //打开输出文件。目标文件 11 FileOutputStream fis= 12 new FileOutputStream("fos_copy.txt"); 13 //读一个byte,写一个byte 14 int d=-1; 15 while((d=fos.read())!=-1){ 16 //d 就是原文件每个byte 17 fis.write(d); 18 } 19 //采用数组作为缓冲区进行读取。 20 // int n; 21 // byte[] buf = new byte[1024*8]; 22 // while((n = in.read(buf))!=-1){ 23 //每次写入几个字节 24 // out.write(buf, 0, n); 25 // } 26 System.out.println("复制完毕"); 27 fos.close(); 28 fis.close(); 29 } 30 }
(5)//实现复制文件的过程批量的操作字节数据
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 public class FOSDemo05 { 6 public static void main(String[] args) throws IOException { 7 FileInputStream fis= 8 new FileInputStream("fos.txt"); 9 FileOutputStream fos= 10 new FileOutputStream("fos_copy.txt"); 11 int len=-1; 12 //采用数组作为缓冲区进行读取。 13 byte[] buf=new byte[32]; 14 //读取数据写错了,len=fis.read(),这样读入的就不是数组buf 15 while((len=fis.read(buf))!=-1){ 16 fos.write(buf,0,len); 17 } 18 System.out.println("复制完毕"); 19 //经常性的忘记写关闭文件语句 20 fis.close(); 21 fos.close(); 22 } 23 }
(6)缓冲流
BufferedOutputStream缓冲输出流内部也维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。为此我们可以使用缓冲输出流来一次性批量写出若干数据减少写出次数来提高写 出效率。
1 //BOS实现写出缓冲 2 import java.io.BufferedOutputStream; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.FileNotFoundException; 6 7 public class FOSDemo06 { 8 public static void main(String[] args) throws IOException { 9 FileOutputStream fos= 10 new FileOutputStream("fos.txt"); 11 /* 12 * 只需要将BufferedOutputStream 套在fos 13 * 外面就可以自动增加缓冲区处理。 14 */ 15 BufferedOutputStream bos= 16 new BufferedOutputStream(fos); 17 //所有字节被存入缓冲区,当缓冲区满了会自动的写到文件中(等待一次性写出) 18 bos.write("HelloWorld".getBytes()); 19 //关闭缓冲字节输出流之前,会将缓冲区的内容一次性写出 20 //错写成fos.close()----文件中数据没有被写入 21 bos.close(); 22 /* 23 * bos.close() 清空缓冲,关闭文件 24 * 执行以后,文件流不能再写数据了。 25 * bos.flush() 清空缓冲,文件还是打开的 26 * 还可以继续写 写数据。 27 */ 28 } 29 }
BufferedInputStream是缓冲字节输入流。其内部维护着一个缓冲区(字节数组),使用该流在读取一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据被全部读取完毕,会再次读取若干字节从而反复。这样就减少了读取的次数,从而提高了读取效率。
BIS是一个处理流,该流为我们提供了缓冲功能。
1 //BIS实现输入缓冲 2 import java.io.BufferedInputStream; 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 public class FOSDemo07 { 7 public static void main(String[] args) throws IOException { 8 FileInputStream fos= 9 new FileInputStream("fos.txt"); 10 BufferedInputStream bos= 11 new BufferedInputStream(fos); 12 int len=-1; 13 while((len=bos.read())!=-1){ 14 //这个地方输出的是len!!! 15 System.out.print((char)len+" "); 16 } 17 //笨啊,又忘记关闭文件了!!! 18 bos.close(); 19 } 20 }
(7)//基于缓冲区实现文件的复制
1 import java.io.BufferedInputStream;
2 import java.io.BufferedOutputStream;
3 import java.io.FileInputStream;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7
8 public class FOSDemo08 {
9 public static void main(String[] args) throws IOException {
10 //只要在原有流上扩展使用 BIS BOS 就可以
11 //大幅提高软件性能!所以 BIS BOS很常用!
12 //在应用中,打开文件,就会加上缓冲流,提高IO性能
13 /*
14 * 使用数组实现的优化算法,永远是最快的
15 * 但是比较繁琐的!容易出现Bug!开发效率低!
16 */
17 FileInputStream fis=
18 new FileInputStream("fos.txt");
19 BufferedInputStream bof=
20 new BufferedInputStream(fis);
21 FileOutputStream fos=
22 new FileOutputStream("fos_copy2.txt");
23 BufferedOutputStream bof1=
24 new BufferedOutputStream(fos);
25 int len=-1;
26 while((len=bof.read())!=-1){
27 //实现文件复制,不是输出读取的字节数据
28 //System.out.print((char)len+" ");
29 bof1.write(len);
30 }
31 System.out.println("复制完毕");
32 bof.close();
33 bof1.close();
34 }
35 }
(8) 对象序列化
对象是存在于内存中的。有时候我们需要将对象保存到硬盘上,又有时我们需要将对象传输到另一台计算机上等等这样的操作。这时我们需要将对象转换为一个字节序列,而这个过程就称为对象序列化。相反,我们有这样一个字节序列需要将其转换为对应的对象,这个过程就称为对象的反序列化。
1 import java.io.Serializable; 2 public class Emp implements Serializable{ 3 // ObjectOutputStream在对对象进行序列化时有一个要求,就是需要序列化的对象所属的类必须实现Serializable接口。 4 private static final long serialVersionUID=1L; 5 /* 6 * 实现序列化接口,最好添加 serialVersionUID 7 * 这样可以保持类的版本稳定,避免序列化问题,提高 8 * 序列化的稳定性! 9 */。 10 protected String name; 11 protected transient int age; 12 /* 13 * transient属性在序列化时候,这个属性会被 14 * 自动忽略!可以避免将不需要的属性进行序列化 15 * 保存。反序列化时候,值是null 16 * 17 */ 18 // protected int age; 19 protected char gender; 20 protected double salary; 21 public Emp(){ 22 } 23 public Emp(String name,int age,char gender,double salary){ 24 super(); 25 this.name=name; 26 this.age=age; 27 this.salary=salary; 28 this.gender=gender; 29 } 30 public int getAge() { 31 return age; 32 } 33 public void setAge(int age) { 34 this.age = age; 35 } 36 public char getGender() { 37 return gender; 38 } 39 public void setGender(char gender) { 40 this.gender = gender; 41 } 42 public double getSalary() { 43 return salary; 44 } 45 public void setSalary(double salary) { 46 this.salary = salary; 47 } 48 public void setName(String name) { 49 this.name = name; 50 } 51 public String toString(){ 52 return name+","+age+","+gender+","+salary; 53 } 54 }
1 //实现Emp的序列化 2 import java.io.FileNotFoundException; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.ObjectOutputStream; 6 public class FOSDemo09 { 7 public static void main(String[] args) throws IOException { 8 /* 9 * 创建对象输出流,对象流是一个扩展流(高级流) 10 * 对象输出流必须依赖于字节节点流。 11 */ 12 FileOutputStream fos= 13 new FileOutputStream("fos1.txt"); 14 ObjectOutputStream oos= 15 new ObjectOutputStream(fos); 16 Emp emp=new Emp("王五",25,'男',50000); 17 //对象输出流会自动将对象序列化为byte数据写到文件中。 18 oos.writeObject(emp); 19 System.out.println("序列化完毕"); 20 /* 21 * 关闭高级流,底层的节点流就自动关闭了。 22 */ 23 oos.close(); 24 } 25 }
运行方法,在当前工程下生成了文件fos1.obj,该文件的内容是二进制输入,无法读懂其中的内容。
1 //Emp的反序列化 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.IOException; 5 import java.io.ObjectInputStream; 6 7 public class FOSDemo10 { 8 public static void main(String[] args) throws IOException, ClassNotFoundException { 9 FileInputStream fos= 10 new FileInputStream("fos1.txt"); 11 ObjectInputStream ois= 12 new ObjectInputStream(fos); 13 /* 14 * readObject方法会从底层的节点流中读取字节,并反序列化为对象。 15 * 返回类型是Object类型。需要类型转换 16 * 这个类型一定与写文件时候的类型一致!否则会出现异常。 17 */ 18 Emp emp=(Emp)ois.readObject(); 19 System.out.println("反序列化成功"); 20 System.out.println(emp); 21 ois.close(); 22 } 23 }
(9)指定字符编码
1 import java.io.FileNotFoundException; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.OutputStreamWriter; 5 import java.io.UnsupportedEncodingException; 6 public class FOSDemo11 { 7 public static void main(String[] args) throws IOException{ 8 FileOutputStream fos= 9 new FileOutputStream("demo.txt"); 10 /* 11 * 字符流是 扩展流,必须依赖字节节点流! 12 */ 13 OutputStreamWriter os= 14 new OutputStreamWriter(fos,"UTF-8"); 15 //这里使用的字符编码为UTF-8 16 String str="大家好";//UTF-8中文为3个字节,英文符号占1个字节 17 /* 18 * 字符流输出方法会自动将文字进行编码处理, 19 * 变成byte数据写到底层的字节流中 20 */ 21 os.write(str); //写出后该文件大小应该为10字节 22 os.close(); 23 /* 24 * 什么是文本文件? 25 * 将字符按照一定的编码规则进行编码,得到 26 * byte数据,保存这些byte数据的文件,称为 27 * 文本文件! 28 * 字符不能直接保存到文件,文件中存储的是 29 * 字符的编码结果! 30 */ 31 } 32 } 33 public class FOSDemo12 { 34 public static void main(String[] args) throws IOException { 35 FileInputStream fos= 36 new FileInputStream("demo.txt"); 37 InputStreamReader read= 38 new InputStreamReader(fos,"UTF-8"); 39 int len=-1; 40 /* 41 * reader.read() 是自动从底层 字节输入流 42 * 中读取编码数据,对编码进行解码 43 * 处理,返回解码的字符! 44 */ 45 while((len=read.read())!=-1){ 46 System.out.println((char)len); 47 } 48 read.close(); 49 } 50 }

浙公网安备 33010602011771号