IO的基础知识
- IO流是什么
- 读取和存储数据的解决方案
IO流的方向
操作文件类型
字节流:操作所有文件
字符流:操作txt纯文本文件:txt,md
IO学习
字节流
输出数据
public static void main(String[] args) throws IOException {
//1. 输出文件
FileOutputStream f = new FileOutputStream("E://05输出//123.txt");
//2. 写入
f.write(97); //output:a
//3. 关闭通道
f.close();
}
- 创建字节输出流对象
- 细节1:字符串路径或者File对象都可以
- 细节2:如果文件不存在会创建一个新的文件,要保证父路径存在
- 细节3:如果文件已经存在。会被清空重写
- 写入数据
- 写入的数字是对应ASCII码
- 释放资源
- 解除了资源的占用
Write 的使用方法
字节写入的三种方式
- 直接写入f.write(97)
- 通过字节数组写入
byte[] bytes = {97, 98, 99, 100};
f.write(bytes);
- 写入字节数组的一部分
/*
off:开始的位置
len:个数
*/
byte[] bytes = {97, 98, 99, 100};
f.write(bytes,1,2);
换行和续写
原理:
- 使用一个String字符串,使用其getbytes()得到字节数组,然后再输入到f.write()
换行:
String wrap = "\r\n";
byte[] bytes1 = wrap.getBytes();
fos.write(bytes1);
续写:当你使用FileOutputStream的时候,第二个参数设置为true即可以续写
FileOutputStream fos = new FileOutputStream("E://05输出//123.txt",true);
输入数据
- 因为是字节,所以输入到java只有一个字符
int b = f.read();
sout((char)b); ->转换为字符
如何在java上连续显示字符
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\03存储\\BaiduSyncdisk\\study\\java\\String\\String001\\a.txt");
int b;
while((b = fis.read()) != -1){
System.out.print((char)b);
}
fis.close();
}
拷贝数据
第一种方案:边写边读
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\03存储\\onedrive\\桌面\\123.txt"); //读
FileOutputStream fos = new FileOutputStream("D:\\03存储\\onedrive\\桌面\\论文阅读\\321.txt");//写
int b;
while((b = fis.read()) != -1){
fos.write(b);
}
//哪一个方法先使用 就最后 关闭
fos.close();
fis.close();
}
第二种方案:使用read读取的时候,创建一个数组固定接受字节 read(bytes)->一次性接受bytes个字节读取
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\03存储\\onedrive\\桌面\\123.txt"); //读
FileOutputStream fos = new FileOutputStream("D:\\03存储\\onedrive\\桌面\\论文阅读\\321.txt");//写
int b;
byte[] bytes = new byte[2];//使用数组读取 加快速度
while((b = fis.read(bytes)) != -1){ //当阅读到最后一个字符后会显示-1 即停止阅读
String str = new String(bytes);
System.out.println(str);
fos.write(b);
}
//哪一个方法先使用 就最后 关闭
fos.close();
fis.close();
}
小科普 如何获取一个程序的运行时间
//使用开始时间和结束时间
long start = System.currentTimeMills();
...
long end = System.currentTimeMills();
end - start
字符集详解
计算机存储规则
在计算机中,任意数据都是以二进制存储的
当存储英文,1个字节就够了
一般来说存储中文,需要 3 个字节,因为使用的都是 Unicode
ASCII字符集
GBK字符集
Unicode 万国码
UTF-8不是字符集 是一种编码方式
中文:3个字节
英文:1个字节
为什么会有乱码
- 读取数据的时候未完整读取整个汉字
- 编码和解码的方式不统一 (最重要的)
如何不产生乱码
1,不要用字节流读取文本文件
2,编码解码时使用同一个码表,同一个编码方式
为什么拷贝不会产生乱码
因为拷贝是一个字节一个字节进行输入的,不会产生损失
编码和解码代码实现
public static void main(String[] args) throws UnsupportedEncodingException {
//1. 编码
String str = "ai你哟";
byte[] bytes = str.getBytes();
System.out.println(Arrays.toString(bytes));
//2. 解码
String s = new String
bytes);
System.out.println(s);
//使用错误的编码方式
String s1 = new String(bytes, "GBK");
System.out.println(s1);
}
字符流
- 字符流
- 底层是字节流
- 底层是字节流
字符流的体系
READ
空参read读取
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\03存储\\onedrive\\桌面\\1.txt");
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
}
带参read读取
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\03存储\\onedrive\\桌面\\1.txt");
char[] chars = new char[2];
int len;
while((len = fr.read(chars)) != -1){
System.out.print(new String(chars,0,len));
}
fr.close();
}
有参read和无参read有什么区别吗?
无参:读取数据->解码(转换为十进制)
有参:读取数据->解码->强制类型转换(得到的结果是字符的长度,读取的内容已经放置在后面的数组中)
FileWriter
构造方法
成员方法
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:\\03存储\\onedrive\\桌面\\1.txt",true);
char[] chars = {'为','什','么','显','示','错','误'};
fw.write(chars); //可以数组也可以直接以String类型输入
fw.close();
}
tips
如果创建了一个相同名字的文件,则之前的文件内容会被清空
缓冲流
字节缓冲流
- 自带 8192 的缓冲区
代码如下所示:
字节缓冲流提高效率的原理
因为在内存中处理速度非常快,所以无论是字节还是字节数组,传输数据都很快
字符缓冲流
对于字符流缓冲并不明显,但是有两个特有的方法
- BufferedReader:readLine()
- 读取一行的数据
- BufferedWriter:newLine()
- 写入的时候可以换一行写入
newLine():
readLine():
转换流
- 字节流和字符流之间的桥梁
作用:
- 指定字符集读写(已淘汰)
- 字节流想要使用字符流中的方法
可以读取不同类型的文本,比如GBK
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\03存储\\onedrive\\桌面\\gbkfile.txt"),"GBK");
int ch;
while ((ch = isr.read()) != -1){
System.out.print((char)ch);
}
}
一样的效果:
FileReader gbk = new FileReader("D:\\03存储\\onedrive\\桌面\\gbkfile.txt", Charset.forName("gbk"));
写出不同的编码方式
gbk读取,utf-8写入
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\01代码\\java001\\demodemo1\\a.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\01代码\\java001\\demodemo1\\b.txt"), "UTF-8");
int ch;
while ((ch = isr.read()) != -1) {
osw.write(ch);
}
osw.close();
isr.close();
}
序列化流 ObjectOutputStream
- 把java中的对象写到本地文件
- 使用对象输出流保存会出现NotSerializableException异常
- 让javabean类实现Serializable接口
代码:
- 让javabean类实现Serializable接口
public static void main(String[] args) throws IOException {
student s1 = new student("zhangsan", 23);
//创建序列化流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\03存储\\onedrive\\桌面\\新建 文本文档.txt"));
oos.writeObject(s1);
oos.close();
}
反序列化流 ObjectInputStream
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\03存储\\onedrive\\桌面\\新建 文本文档.txt"));
Object object = (Student)ois.readObject();
System.out.println(object);
ois.close();
}
序列化和反序列化流的细节
- 当你修改代码类后,读取的之前类会出现错误
- 解决方案:写一个相同的版本号
需要在写完所有的类最后写版本号
- 解决方案:写一个相同的版本号
设置Serializable
- 在设置中搜索Serializable
//添加的版本号:
@Serial
private static final long serialVersionUID = -5806700070317353843L;
如果在序列化的过程中不想把某个元素序列化怎么办?
添加一个瞬态关键字:transient,那么在读取的过程中这个address就是null,原来的值会被隐藏
如何解决添加多个对象后读取不知道有多少个对象?
解决问题:
添加多个对象后,把对象封装在集合中,然后读取时读取的是集合,这样全部就可以读取出来了。
序列化作业
输入对象到文件
public static void main(String[] args) throws IOException {
Student s1 = new Student("zhangsan", 23, "南京");
Student s2 = new Student("wangwu", 21, "北京");
Student s3 = new Student("lisi", 14, "东京");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\03存储\\onedrive\\桌面\\新建 文本文档.txt"));
ArrayList<Student> students = new ArrayList<>();
Collections.addAll(students,s1,s2,s3);
oos.writeObject(students);
oos.close();
}
读取对象到java
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\03存储\\onedrive\\桌面\\新建 文本文档.txt"));
ArrayList<Student> ss = (ArrayList<Student>)ois.readObject();
ss.stream()
.forEach(s -> System.out.println(s));
}
打印流
打印流只有输出流
特点:
字节打印流
示例:
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream(new FileOutputStream
("D:\\03存储\\onedrive\\桌面\\新建 文本文档.txt"),true, Charset.forName("utf-8"));
ps.println("hello world");
ps.print(98);
ps.printf("哈哈哈");
ps.close();
}
字符打印流
字符打印流有缓冲区,想要自动刷新需要开启
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("E:\\01代码\\java001\\demodemo1\\a.txt"),true);
pw.println("hello worldhahahhahahhahhahah");
pw.print("hahahha");
pw.close();
}
打印流什么时候使用
- 字节打印流
- 字符打印流
特点: - 打印流不能操作数据源,只能操作目的地
- 也就是说只能输入,无法修改
- 字节打印流
- 默认自动刷新
- 字符打印流
- 自动刷新需要开启
我们在日常输出的时候就会使用打印流进行输出
public static void main(String[] args) {
PrintStream out = System.out;
out.println("hello world");
// out.close();
System.out
.println("helo world");
}
解压缩流、压缩流
常用工具包
Commons-io
- 创建一个文件夹lib专门存放第三方java包
- 把jar赋值到lib文件夹
- 右键点击jar选择add as library
- 在类中导入包
public static void main(String[] args) throws IOException {
File src = new File("E:\\01代码\\java001\\demodemo1\\a.txt");
File dest = new File("E:\\01代码\\java001\\demodemo1\\b.txt");
FileUtils.copyFile(src, dest);
}
hutool
public static void main(String[] args) {
File file = FileUtil.file("D:\\test\\1.txt");
//touch 根据参数直接创建文件
System.out.println(FileUtil.touch(file));
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3","4","5","add");
//将集合写入文件
File file1 = FileUtil.writeLines(list, "D:\\test\\1.txt", "utf-8");
//追加写入文件
FileUtil.appendLines(list, "D:\\test\\1.txt", "utf-8");
System.out.println(file1);
//读取文件并且写入集合中
ArrayList<String> list1 = FileUtil.readLines("D:\\test\\1.txt", "utf-8", new ArrayList<String>());
List<String> list2 = FileUtil.readLines("D:\\test\\1.txt", "utf-8");
System.out.println(list2);
}