JAVA小白的崛起之路(十二)IO
IO操作步骤
在进行任何操作之前,首先要明确目的(读还是写),找准源头(读取),找准目 的地(写出)。
- 建立联系 :这一步骤是为了获取流,如果此时是文件,则需要将文件抽象到 内存形成对象。后期也可以是其他的数据源
- 选择流:从读写、数据单元和功能方面考虑。输入|输出,字节|字符,结点流| 处理流。
- 执行操作:该读就读,该写就写。考虑是一次性完成还行需要循环。
- 释放资源:程序中打开的文件 IO 资源不属于内存中的资源,垃圾回收无法回 收,需要显示关闭
读取
public class Test02 {
public static void main(String[] args) throws IOException {
//建立联系 File 对象 路径
File file =new File("a.txt");
//选择流 抛出IO流父类异常 IOException
InputStream is = new FileInputStream(file);
//执行操作
//创建一个用于判断数据是否结束 -1
int len;
//创建一个数组存储数据 每次读取数组长度的数据 快速
byte [] bytes = new byte[1024];
//判断是否结束
while ((len=is.read(bytes))!=-1){
//输出
System.out.println(new String(bytes,0,len));
}
//关闭流
is.close();
}
}
写入
public class Test03 {
public static void main(String[] args) throws IOException {
//1、建立联系 File对象 源头 目的地
//若没有目标文件 则创建一个新的文件
File file = new File("b.txt");
//选择流
OutputStream os = new FileOutputStream(file);
//需要写入的字符串
String str="you're a good person\r\n good good good person";
//字符串转成字节数组
// 可以选择写入的 格式 UTF-8 GBk 根据需要
byte[] data=str.getBytes("utf-8");
//写入
os.write(data,0,data.length);
//刷出 每次写入后尽量刷出 否则 结果可能出现问题
os.flush();
//关闭流
os.close();
}
}
文件复制
运用读取和写入完成文件的复制
public class Demo009CopyStream {
public static void main(String[] args) throws IOException {
// 源头
File src = new File("test.png");
// 目的地
File dest = new File("testcopy.png");
InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dest);
byte[] car = new byte[2];
int len ;
while((len=is.read(car))!=-1){
os.write(car,0,len);
}
os.flush();
os.close();
is.close();
}
}
字节流可以操作所有文件,字符流仅操作纯文本
缓冲处理类:
BuweredInputStream和 BuweredReader:
缓冲提高性能: 字节流缓冲流直接套在节点流上即可使用;字符缓冲流 +新增方法(不能使用多态),具体操作很简单,只需要直接在字节流操作的基础上“套上”缓冲流即可
//缓冲流字节读入
InputStream is =new BufferedInputStream(new FileInputStream(file));
//缓冲流字节写出
OutputStream os=new BufferedOutputStream(new FileOutputStream(file));
//缓冲流字符读入
BufferedReader br =new BufferedReader(new FileReader(file));
//缓冲流字符写出
BufferedWrite br =new BufferedWrite(new FileWrite(file));
//缓冲流字符读入
BufferedReader br =new BufferedReader( new InputStreamReader(new BufferedInputStream(new FileInputStream(src)),"utf-8" ) );
转换处理流: InputStreamReader
数据处理流:
DataInputStream和 DataOutputStream
//创建源
File dest = new File("");
//选择流
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
对象流
以前我们学过的流都只能读写字节,字符形式的数据,而java中非常重要并且常见 的对象类型的数据,如果想要存储到文件中应该怎么操作呢?这个时候就使用到了 对象流。
序列化:是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中 或通过网络发送到任何其他程序
反序列化:从字节流创建对象的相反的过程称为 反序列化
ObjectOutputStream(序列化)
首先在使用ObjectInputStream和ObjectOutputStream的时候,放置在此IO中的对 象,必须要实现Serializable接口!序列化接口(实现了此接口,代表我们的对象支 持序列化)
但是实现了Serializable接口之后,其中并没有实现任何方法,对于这种接口,我们 称之为标记接口。
注意: 要先序列化后反序列化
//创建源
File dest=new File(destPath);
//选择流
OjbectOutputStream ObjectOutputStream dos=new ObjectOutputStream( new BufferedOutputStream(new FileOutputStream(dest)) );
//操作 读取的顺序与写出的顺序一致 必须存在才能读取
Employee obj=new Employee ("yinwei",1500); dos.writeObject(obj);
//刷出
dos.flush();
//释放资源
dos.close();
对象处理流(反序列化):ObjectInputStream
ObjectInputStream能够让你从输入流中读取Java对象,而不需要每次读取一个字 节。你可以把InputStream包装到ObjectInputStream中,然后就可以从中读取对象 了。
transient 瞬时的,属性被该关键字修饰,则不会序列化。反序列化的时候,则 使用属性默认值
File file = new File("a.txt");
// 选择流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
// 写数据
Student stu = new Student("zas",18,false);
/*stu.setAge(20); stu.setGender(true); stu.setName("zs");*/
oos.writeObject(stu); oos.flush();
// 释放资源
oos.close();
/** * 反序列化:
* 1、先写入再读取
* 2、读取对象需要知道具体类型,依次读取
* 注意:
* 1)不是所有的对象都可以序列化 Serializable
* 2)不是所有的属性都需要序列化 transient
*/
public static void read(String srcPath) throws FileNotFoundException, IOException, ClassNotFoundException{
//创建源
File src=new File(srcPath);
//选择流
OjbectInputStream ObjectInputStream dis=new ObjectInputStream( new BufferedInputStream( new FileInputStream(src) ) );
//操作 读取的顺序与写出的顺序一致 必须存在才能读取
Object obj=dis.readObject();
if(obj instanceof Employee){
Employee emp=(Employee)obj;
System.out.println(emp.getName());
System.out.println(emp.getSalary());
}
obj=dis.readObject();
int[]arr=(int[])obj;
System.out.println(Arrays.toString(arr));
//释放资源
dis.close();
}
总结
从不同维度将IO 进行分类
按照数据流的方向不同可以分为:输入流和输出流。
输入流:文件写入到程序中
输出流:程序写出到文件中
按照处理数据单位不同可以分为:字节流和字符流。
字节流:一次读入或读出是8位二进制。
字符流:一次读入或读出是16位二进制。
按照实现功能不同可以分为:节点流和处理流。
节点流:直接与数据源相连,读入或读出。
处理流:与节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。
输入流:数据源到程序(InputStream
、Reader读进来)
输出流:程序到目的地(OutPutStream
、Writer写出去)
字节流与字符流之间的区别:
1.读写单位不同:字节流式以字节(8位2进制)为单位,字符流是以字符为单位,根据码表映射字符,一次可能读多个字节。
2.处理对象不同:字节流能处理所有类型的数据(如图片、视频,音频等),而字符流只能处理字符类型的数据。
3.一次读入或读出是8位二进制。
4.字符流:一次读入或读出是16位二进制。
结论:只要是纯文本数据优先使用字符流,除此之外都使用字节流。