hi,我是逸尘,一起学java吧
目标(任务驱动)
1.请重点的掌握I/O的。
场景:最近你在企业也想搞一个短视频又想搞一个存储的云盘,你一听回想到自己对于这些存储的基础还不是很清楚,于是回家开始了复习基础。
我们前面学习了变量,数组,集合,但是我们发现那些都是暂时存在的,一旦关闭电脑或者程序,那么就会空空如也。那么我们想要不丢失文件,永久的存储程序创建的数据,就需要保存到磁盘中,也就是内存数据存储到磁盘文件中,我们也称之为持久化。我们可以使用java的I/O技术将数据保存到文本,二进制文件,甚至是zip压缩包中,达到永久保存。
流
流是一组有序的数据序列 (我们之前的Stream是处理流,不是这个流。)
可以理解为在计算机中两个不同位置之间建立的一个通道·,该通道用于传输数据。
输入输出流
我们根据流操作的正反方向划分,我们可以分为输入和输出流两种。
如果我们想对象序列化,程序内容对象到磁盘等外部,我们是输出流,正向的。
ps;我们以程序为根本(锚点)外部为目标 判断方向,所以是输出
反而言之反序列化就是输入流,反向的。
虽然说I/O流通常是与磁盘文件存取有关,但是也可以是鼠标键盘内存或者显示器为目的地/源。
字符字节流
我们在最开始的章节学习了,计算机底层存储只能是二进制的,字节(Byte)是二进制数据的单位,一个字节存储8位无符号数,我们也学习了字符集,在不同的编码方式下,一个字符占的字节可能不一样,以UTF-8的编码来看,中文一般占三个字节。
我们根据数据单位规格来区分又可以分为字符流和字节流。
总结
那么根据这些划分的不同,我们可以整理一下IO流体系
I/O流体系
我们的字节流可以做一切的文本数据拷贝,但是不适合读文本内容,涉及到处理字符文本我们优先考虑字符流(英文一个字节还好说,但是中文不是,那么就适合直接使用字符为单位处理)。
一些方法
读的API
写的API
File类
我们介绍了,I/O流,我们发现需要获取文件,文件夹在磁盘的定位,用来获取或者删除,或者其他操作信息。在java中,我们有File类定义了一些用来操作文件的方法。
它有三种常用的构造方法
相对路径和绝对路径
绝对路径:以windows操作系统为例,包括盘符在内的文件或文件目录的完整路径,固定的位置。
或者可以右键鼠标的属性找到
相对路径:相对于某一个文件目录来讲的相对的位置,它是依靠一个文件作为一个定位。
在idea中,如果使用单元测试方法:相对于当前的module来讲
如果使用main()方法:相对于当前的project来讲
创建一个文件
package com.yd.yc;
import java.io.File;
public class FileOne {
public static void main(String[] args) {
//注意绝对路径名前要用\\ 而不是\
// "/" 分隔符,"\" 转义字符
// File file = new File("D:\\aaa.txt");
File file = new File("D:/aaa.txt");
//相对路径请按照自己项目
// File file = new File("src\\com\\yd\\yc\\8888.txt");
if (file.exists()){
file.delete();
System.out.println("文件删除");
}else{
try {
file.createNewFile();
System.out.println("文件已创建");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
有的朋友相对路径不正确,看看自己的运行工作目录
需要注意一下的是在运行配置地址
工作目录要注意一下
常见的其他File的一些API
需要注意一下
还有一个
public file[] listfiles()
获取当前目录下所有的"一级文件对象"到一个文件对象数组中去返回
package com.yd.yc;
import java.io.File;
public class FileTwo {
public static void main(String[] args) {
File file = new File("src\\com\\yd\\yc");
File fileOne = new File("src\\com\\yd\\yc\\www");
if (file.exists()){
//创建一个一级文件夹
fileOne.mkdir();
String name = file.getName();//获取文件名称
file.length();//获取文件长度
file.isHidden();//是否是隐藏文件
file.lastModified();//最后修改文件的时间
File[] files = file.listFiles();//获取文件目录西安
for (File o: files){
System.out.println(o.getName());
}
System.out.println("文件夹名称 "+name);
}else{
System.out.println("文件不存在");
}
}
}
输入输出字节流
回到我们的I/O流,我们在字节流中有两个实现类FileInputStream和FileOutPutStream接下来我们要介绍一下这两个类
FileInputStream和FileOutPutStream
这两个类分别提供了操作磁盘文件的读和写的能力(相对简单的读文件可以使用FileInputStream)
示例一 读写操作
package com.yd.yc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class IoOne {
public static void main(String[] args) {
File file = new File("src\\com\\yd\\yc\\8888.txt");
try {
//写
//创建一个字节输出流
FileOutputStream out = new FileOutputStream(file);
//字节 内存对象数据
//String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组。
byte[] buy="家人们谁懂呀,我真的要无语死了".getBytes();
//FileOutputStream的写方法
out.write(buy);
//关闭字节流
out.close();
//读
//创建一个字节输入流
FileInputStream in = new FileInputStream(file);
//缓存字节数组,如果不够中文是三个字节,4个字节会乱码一个
byte[] buffer=new byte[4];
//FileInputStream的写方法
int read = in.read(buffer);
System.out.println(new String(buffer,0,read));
}catch (Exception e){
e.printStackTrace();
}
}
}
示例二 拷贝资源
/**
* 拷贝资源
*/
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class CopyDemo {
public static void main(String[] args) {
//创建一个字节输入流管道(接入原视频)
try {
FileInputStream is = new FileInputStream("C:\\迅雷云盘\\b站\\666.flv");
//接通目标(复制)
FileOutputStream os = new FileOutputStream("one/src/new.flv");
//定义一个字节数组转移数据
byte[] buffer=new byte[1024];
int len;//记录读取字节数
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
}
System.out.println("复制完毕");
os.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输入输出字符流
FileReader和FileWriter
字符流中有Reader抽象类是输入流处理字符的简化,Writer也是输出流的字符简化,他们对应的两个实现类FileReader和FileWriter,接下来我们要介绍一下这两个类
字符流读取文本特别是中文不会出现乱码的情况,但是性能比较慢
package com.yd.yc;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class IoTwo {
public static void main(String[] args) throws IOException {
//写出,程序输出流,创建一个字符输出流的管道
FileWriter fileWriterOne = new FileWriter("src\\com\\yd\\yc\\8888.txt");
//源数据
String word="大江东去浪淘尽";
fileWriterOne.write(word);
fileWriterOne.close();
//读,程序输入流
FileReader fileReaderOne = new FileReader("src\\com\\yd\\yc\\8888.txt");
//缓存字符数组
char[] buffer = new char[1024];
int len;
//读入(放入)缓存数组中, 如果读完就返回-1,没读完继续
//buffer中可能就有[大江东去浪淘尽]
while ((len=fileReaderOne.read(buffer))!=-1){
String s = new String(buffer, 0, len);
System.out.println(s);
}
fileReaderOne.close();
}
}
总结一下
高级流
在之前我们所学的是基础流 ,我们接下来学习高级流,需要注意的是高级流是要 包装低级流的
缓冲流
我们之前学习的流都是属于基础流,性能其实不是最好的,缓冲流读写数据的性能会更好一些 。
缓冲流也称为高效流 或者高级流。之前学习的字节流可以称为原始流。缓冲流自带缓冲区, 以提高原始字节流,字符流读写数据的性能。
字节缓冲流性能优化原理:
字节缓冲输入流自带了8kb缓冲池,以后我们直接从缓冲池读取数据,所以性能较好。
字节缓冲输出流自带了8kb缓冲池,数据就直接写入到缓冲池中去,写数据性能极高了。
package com.yd.yc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class IoSix {
public static void main(String[] args) throws Exception {
File file = new File("src\\com\\yd\\yc\\8888.txt");
//低级流
FileReader fileReader = new FileReader(file);
//包装低级流
BufferedReader bufferedReader = new BufferedReader(fileReader);
String len;
//readLine读取一行数据,一行无了就返回null
while ((len=bufferedReader.readLine())!=null){
System.out.println(len);
}
bufferedReader.close();
}
}
对象序列化与反序列化
那么学习流的其他内容,我们先谈谈序列化
序列化不一定要持久化,但是序列化为持久化做了格式的处理
与之相反还有反序列化,我们将磁盘中的对象数据恢复到内存对象中。
对象字节输出流objectoutputstram,在实现序列化对象的要求是对象必须实现序列化接口,
implements Serializable
对象反序列化用到了对象字节输入流objectlnputstram 类方法是 public object readobject()
package com.yd.yc;
import java.io.*;
public class IoFive {
public static void main(String[] args) throws Exception {
Employee employee = new Employee("小尘", 40, 1111, "男", "环卫工");
File file = new File("src\\com\\yd\\yc\\999.txt");
//字节输出流,管道
FileOutputStream fileOutputStream = new FileOutputStream(file);
//对象序列化,管道包装成高级流,高级输出流
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//调用序列化方法
objectOutputStream.writeObject(employee);
//释放资源
objectOutputStream.close();
System.out.println("序列化完成");
//低级流 输入流 对程序输入
FileInputStream inputStream = new FileInputStream(file);
//变成高级流
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
//方法读
Object o = objectInputStream.readObject();
System.out.println(o);
}
}
打印流
打印流一般是指:printstream,printWrite两个类,该对象具有特有的方法,print println可以打印任何数据类型的数据。
特有的printf方法可以保持任意类型的数据表现形式的原样性,将数据输出到目的地(而Out
putStream父类中的write是将数据的字节写出去)
可以实现打印什么数据就是什么数据。
什么时候用?当需要保证数据表现的原样性时,就可以使用打印流的打印方法来完成,保证(表现形式)原样性的原理:其实就是将数据变成字符串,再进行写入操作。
package com.yd.yc;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class IoSeven {
public static void main(String[] args) throws FileNotFoundException {
//1.创建打印流
PrintWriter pw=new PrintWriter("src\\com\\yd\\yc\\8888.txt");
//2.打印
pw.println(97);
pw.println(true);
pw.println(3.14);
pw.println('a');
pw.flush();
//3.关闭
pw.close();
System.out.println("打印完毕");
}
}
转换流
如果我们的代码和文件编码不一致,字符流读取会乱码,这个时候需要我们的转换流。
我们先获取原有的字节流,使用转化流且参数可以指定编码,这样就不会乱码了。
package com.yd.yc;
import java.io.*;
public class IoSeven {
public static void main(String[] args) throws Exception {
//1.创建字节输出流
OutputStream ot = new FileOutputStream("src\\com\\yd\\yc\\8888.txt");
//2.转换流
OutputStreamWriter ott = new OutputStreamWriter(ot,"UTF-8");
//3.再用缓冲流包装一下
BufferedWriter otts = new BufferedWriter(ott);
otts.write("我爱我的祖国");
otts.close();
}
}