I/O流
- I/O流
- IO流体系
- 字节流体系
- FileOutPutStream(字节输出流)
- FileInPutStream(字节输入流)
- 练习:文件拷贝
- Java中编码与解码的方法
- 字符流
- FileReader
- FileWriter
- 综合练习
- 缓冲流体系
- 字节缓冲流
- 字符缓冲流
- 综合练习2
- 转换流
- 序列化流(对象操作输出流)/反序列化流(对象操作输入流)
- 打印流
- 解压缩流/压缩流
- 常用工具包(Commons-io)
- 常用工具包(hutool)
- 综合练习3
- 制造假数据(网络爬虫)
- 随机点名器
- 登录注册
I/O流
1、什么是IO流?
存储和读取数据的解决方案
I:input O:output
流:像水流一样传输数据
2、IO流的作用?
用于读写数据(本地文件,网络)
3、IO流按照流向可以分为哪两种流?
输出流:程序–>文件
输入流: 文件–>程序
4、IO按照操作文件的类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5、什么是纯文本文件?
用Windows系统自带的记事本打开并且能读懂的文件
txt文件,md文件,xml文件,lrc文件等
IO流体系
1、IO流体系
字节流体系
FileOutPutStream(字节输出流)
用法:操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。
字节输出流的细节:
1、创建字节输出流对象
细节1:参数是字符串表示的路径或者是File对象都是可以的。
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。
细节3:如果文件已经存在,则会清空文件
2、写数据
细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符
3、释放资源
每次使用完流之后都要释放资源
书写步骤:
1、创建字节输出流对象
2、写数据
3、释放资源
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
实现需求:写出一段文字到本地文件中。(暂时不写中文)
*/
//1、创建对象
//写出 输出流 OutPutStream
//本地文件 File
FileOutputStream fos = new FileOutputStream("D:\\Test\\untitled4\\a.txt");
//2、写出数据
fos.write(97);
//3、释放资源
fos.close();
}
}
- FileOutPutStream写数据的三种方式
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo2 {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\Test\\untitled4\\a.txt");
//2、写出数据
// fos.write(97);//a
// fos.write(98);//b
byte[] arr = {97,98,99,100,101};
//fos.write(arr);//abcde
/*
参数1:数组
参数2:起始索引 0
参数3:个数
*/
fos.write(arr,1,2);//bc
//3、释放资源
fos.close();
}
}
- 换行写和续写
换行写:再次写出一个换行符
Windows:\r\n
Linux:\n
Mac:\r
细节:Windows操作系统中也可以只写\r或\n
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo3 {
public static void main(String[] args) throws IOException {
//1、创建对象
FileOutputStream fos = new FileOutputStream
("D:\\Test\\untitled4\\a.txt",true);
//2、写出数据
String str = "abcdef";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
//再次写出一个换行符就可以了
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);
String str2 = "666";
byte[] bytes3 = str2.getBytes();
fos.write(bytes3);
//释放资源
fos.close();
}
}
FileInPutStream(字节输入流)
用法:操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。
字节输入流的细节:
1、创建字节输入流对象
细节1:如果文件不存在,就直接报错
2、写数据
细节1:一次读一个文件,读出来的是数据在ASCII上对应的数字
细节2:读到文件末尾了,read方法返回-1.
3、释放资源
细节:每次使用完流之后都要释放资源
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo4 {
public static void main(String[] args) throws IOException {
/*
实现需求:读取文件中的数据。(暂时不写中文)
*/
FileInputStream fis = new FileInputStream("D:\\Test\\untitled4\\a.txt");
//2、读取数据
int i = fis.read();
System.out.println(i);//97
System.out.println((char) i);//a
int i2 = fis.read();
System.out.println(i2);//-1
//3、释放资源
fis.close();
}
}
- 字节输入流循环读取
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo5 {
public static void main(String[] args) throws IOException {
//1、创建对象
FileInputStream fis = new FileInputStream("D:\\Test\\untitled4\\a.txt");
int b;
//循环读取
//read表示读取数据,而且数读取一个数据就移动一次指针,
// 因此需要第三方变量
while ((b = fis.read()) != -1){
System.out.print((char) b);
}
//3、释放资源
fis.close();
}
}
- FileInputStream一次读多个字节
注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo6 {
public static void main(String[] args) throws IOException {
//1、创建对象
FileInputStream fis = new FileInputStream("D:\\Test\\untitled4\\a.txt");
//2、读取数据
byte[] bytes = new byte[2];
//一次读取多个字节数据,具体读多少,跟数组的长度有关
//返回值:本次读取到了多少个字节数据
int len1 = fis.read(bytes);
System.out.println(len1);//2
String str1 = new String(bytes,0,len1);
System.out.println(str1);//ab
//3、释放资源
fis.close();
}
}
练习:文件拷贝
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test1 {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
//1、创建对象
FileInputStream fis = new FileInputStream("D:\\Test2\\d.txt");
FileOutputStream fos = new FileOutputStream("D:\\Test\\untitled4\\copy.txt");
//2、拷贝
//核心思想:边读边写
int len;
byte[] bytes = new byte[1024];
while ((len = fis.read()) != -1){
fos.write(bytes,0,len);
}
//释放资源
//规则:先开的最后关闭
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
Java中编码与解码的方法
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class ByteStreamDemo7 {
public static void main(String[] args) throws UnsupportedEncodingException {
//1、编码
String str = "ai你哟";
byte[] bytes1 = str.getBytes();
System.out.println(Arrays.toString(bytes1));
byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2));
//2、解码
String str2 = new String(bytes1);
System.out.println(str2);
String str3 = new String(bytes2,"GBK");
System.out.println(str3);
}
}
字符流
- 字符流的底层其实就是字节流
字符流 = 字节流 + 字符集
特点:
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景:
对于纯文本文件进行读写操作
FileReader
1、创建字符输入流对象
细节1:如果文件不存在,就直接报错
2、读取数据
细节1:按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个整数
细节2:读到文件末尾了,read方法返回-1。
3、释放资源
空参的read方法
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo1 {
public static void main(String[] args) throws IOException {
//1、创建对象并关联本地文件
FileReader fr = new FileReader("D:\\Test\\untitled4\\a.txt");
//2、读取数据 read()
//字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
// 如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节
/*
read()细节:
1、read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
2、在读取之后,方法的底层还会进行解码并转成十进制。
最终把这个十进制作为返回值
这个十进制的数据也表示在字符集上的数字
英文:文件里面二进制数据 0110 0001
read方法进行读取,解码并转成十进制97
中文:文件里面的二进制数据 11100110 10110001 10001001
read方法进行读取,解码并转成十进制27721
要看到中文,需要进行强制类型转换
*/
int ch;
while (((ch = fr.read())) != -1){
System.out.print((char) ch);
}
fr.close();
}
}
带参的read方法
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo2 {
public static void main(String[] args) throws IOException {
//1、创建对象
FileReader fr = new FileReader("D:\\Test\\untitled4\\a.txt");
//2、读取数据
char[] chars = new char[2];
int len;
//read(chars): 读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中
//空参的read + 强转类型转换
while ((len = fr.read(chars)) != -1){
//把数组中的数据变成字符串再进行打印
System.out.print(new String(chars,0,len));
}
//3、释放资源
fr.close();
}
}
FileWriter
构造方法:
成员方法:
FileWriter书写细节:
- 创建字符输出流对象
细节1:参数是字符串表示的路径或者File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想清空文件可以打开续写开关 - 写数据
细节:如果write方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符 - 释放资源
细节:每次使用完流之后都要释放资源
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter
("D:\\Test\\untitled4\\a.txt",true);
//fw.write(25105);//我
//fw.write("你好啊!");//你好啊!
//fw.write("你好啊!",0,2);//你好
char[] chars = {'a','b','c','我'};
//fw.write(chars);abc我
fw.write(chars,0,2);//ab
fw.close();
}
}
综合练习
1、拷贝一个文件夹,考虑子文件夹
import java.io.*;
public class Test2 {
public static void main(String[] args) throws IOException {
//1、创建对象表示数据源
File src = new File("D:\\Test2\\ccc");
//2、创建对象表示目的地
File dest = new File("D:\\Test2\\aaa");
//3、调用方法开始拷贝
copydir(src,dest);
}
/*
作用:拷贝文件
参数一:数据源
参数二:目的地
*/
private static void copydir(File src,File dest) throws IOException {
dest.mkdirs();
//1、进入数据源
File[] files = src.listFiles();
//2、遍历数组
for (File file : files) {
if(file.isFile()){
//3、判断文件,拷贝
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(dest,file.getName()));
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}else {
//4、判断文件夹,递归
copydir(file,new File(dest,file.getName()));
}
}
}
}
2、文件加密
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理。
加密原理:对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中。
解密原理:读取加密之后的文件,按照加密的规则反向操作,变成原始文件。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test3 {
public static void main(String[] args) throws IOException {
//1、创建对象关联原始文件
FileInputStream fis = new FileInputStream("D:\\Test2\\a.txt");
//2、创建对象关联加密文件
FileOutputStream fos = new FileOutputStream("D:\\Test2\\b.txt");
//3、加密处理
int b;
while ((b = fis.read()) != -1){
fos.write(b ^ 2);
}
//4、释放资源
fos.close();
fis.close();
}
}
3、修改文件中的数据
文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成以下数据:
1-2-4-7-8-9
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Test4 {
//细节1:文件中的数据不要换行
//细节2:不带bom头
public static void main(String[] args) throws IOException {
//1、读取数据
FileReader fr = new FileReader("D:\\Test\\untitled4\\a.txt");
StringBuilder sb = new StringBuilder();
int len;
while ((len = fr.read()) != -1){
sb.append((char) len);
}
fr.close();
System.out.println(sb);
//2、排序
Integer[] arr = Arrays.stream(sb.toString()
.split("-"))
.map(Integer::parseInt)
.sorted()
.toArray(Integer[]::new);
// String str = sb.toString();
// String[] arrStr = str.split("-");
//
// ArrayList<Integer> list = new ArrayList<>();
// for (String s : arrStr) {
// int i = Integer.parseInt(s);
// list.add(i);
// }
// Collections.sort(list);
// System.out.println(list);
//写出
FileWriter fw = new FileWriter("D:\\Test\\untitled4\\a.txt");
String s = Arrays.toString(arr).replace(", ","-");
String result = s.substring(1, s.length() - 1);
fw.write(result);
fw.close();
// FileWriter fw = new FileWriter("D:\\Test\\untitled4\\a.txt");
// for (int i = 0; i < list.size(); i++) {
// if(i == list.size() - 1){
// fw.write(list.get(i) + "");
// }else {
// fw.write(list.get(i) + "-");
// }
// }
// fw.close();
}
}
缓冲流体系
字节缓冲流
需求:利用字节缓冲流拷贝文件
import java.io.*;
public class BufferedStreamDemo1 {
public static void main(String[] args) throws IOException {
//1、创建缓冲流对象
BufferedInputStream bis = new BufferedInputStream
(new FileInputStream("D:\\Test\\untitled4\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream
(new FileOutputStream("D:\\Test\\untitled4\\copy2.txt"));
//2、循环读取并写到目的地(一次读写多个字节)
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
// int b;
// while ((b = bis.read()) != -1){
// bos.write(b);
// }
//3、释放资源
bos.close();
bis.close();
}
}
字符缓冲流
- 字符缓冲流特有方法
- 字符缓冲输入流
import java.io.*;
public class BufferedStreamDemo2 {
public static void main(String[] args) throws IOException {
//1、创建字符缓冲输入流对象
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\a.txt"));
//2、读取数据
String line;
while (((line = br.readLine()) != null)){
System.out.println(line);
}
//3、释放资源
br.close();
}
}
- 字符缓冲输出流
import java.io.*;
public class BufferedStreamDemo3 {
public static void main(String[] args) throws IOException {
//1、创建字符缓冲输出流对象(开启续写)
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt",true));
//2、写入数据
bw.write("张三");
bw.newLine();//换行
bw.write("李四");
//3、释放资源
bw.close();
}
}
综合练习2
1、修改文本顺序
需求:把《出师表》的文章顺序进行恢复到一个新文件中
方式1:
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Test5 {
public static void main(String[] args) throws IOException {
//1、读取数据
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\csb.txt"));
String line;
ArrayList<String> list = new ArrayList<>();
while ((line = br.readLine())!= null){
list.add(line);
}
br.close();
//2、排序
//排序规则:按照每一行前面的序号进行排序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//获取o1和o2的序号
int i1 = Integer.parseInt(o1.split("\\.")[0]);
int i2 = Integer.parseInt(o2.split("\\.")[0]);
return i1 - i2;
}
});
//3、写出
BufferedWriter bw = new BufferedWriter
(new FileWriter("D:\\Test\\untitled4\\result.txt"));
for (String str : list) {
bw.write(str);
bw.newLine();
}
bw.close();
}
}
方式2:
import java.io.*;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Test5_2 {
public static void main(String[] args) throws IOException {
//1、读取数据
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\csb.txt"));
String line;
TreeMap<Integer,String> tm = new TreeMap<>();
while ((line = br.readLine()) != null){
String[] arr = line.split("\\.");
//0:序号 1:内容
tm.put(Integer.parseInt(arr[0]),arr[1]);
}
br.close();
//2、写出数据
BufferedWriter bw = new BufferedWriter
(new FileWriter("D:\\Test\\untitled4\\result2.txt"));
Set<Map.Entry<Integer,String>> entries = tm.entrySet();
for (Map.Entry<Integer, String> entry : entries) {
String value = entry.getValue();
bw.write(value);
bw.newLine();
}
bw.close();
}
}
2、软件运行次数
实现一个验证程序运行次数的小程序,要求如下:
1、当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2、程序运行演示如下:
第一次运行控制台输出:欢迎使用本软件,第1次使用免费~
第二次运行控制台输出:欢迎使用本软件,第2次使用免费~
第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
第四次以及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~
import java.io.*;
public class Test6 {
public static void main(String[] args) throws IOException {
//1、把文件中的数字读取到内存中
//原则:IO:随用随创建,什么时候不用,什么时候关闭
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\count.txt"));
String line = br.readLine();
br.close();
int count = Integer.parseInt(line);
//表示当前软件又运行了一次
count++;
//2、判断
if(count <= 3){
System.out.println("欢迎使用本软件,第" + count + "次使用免费~");
}else {
System.out.println("本软件只能免费使用3次,欢迎您注册会员后继续使用~");
}
//3、把当前自增之后的count写出到文件当中
BufferedWriter bw = new BufferedWriter
(new FileWriter("D:\\Test\\untitled4\\count.txt"));
bw.write(count + "");
bw.close();
}
}
转换流
- 转换流是字符流和字节流之间的桥梁
- 作用:字节流想要字符流中的方法
1、利用转换流按照指定的字符编码读取(了解)
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class ConvertStreamDemo1 {
public static void main(String[] args) throws IOException {
//JDK11的替代方案
FileReader fr = new FileReader
("D:\\Test\\untitled4\\gbkfile.txt", Charset.forName("GBK"));
//2、读取数据
int ch;
while ((ch = fr.read()) != -1){
System.out.println((char)ch);
}
//3、释放资源
fr.close();
// //1、创建对象并指定字符编码
// InputStreamReader isr = new InputStreamReader
// (new FileInputStream("D:\\Test\\untitled4\\gbkfile.txt"),"GBK");
// //2、读取数据
// int ch;
// while ((ch = isr.read()) != -1){
// System.out.println((char)ch);
// }
// //3、释放资源
// isr.close();
}
}
2、利用转换流按照指定字符编码写出
import java.io.*;
import java.nio.charset.Charset;
public class ConvertStreamDemo2 {
public static void main(String[] args) throws IOException {
//JDK11的替代方案
FileWriter fw = new FileWriter
("D:\\Test\\untitled4\\c.txt", Charset.forName("GBK"));
//2、写出数据
fw.write("你好");
// //3、释放资源
fw.close();
// //1、创建转换流对象
// OutputStreamWriter osw = new OutputStreamWriter
// (new FileOutputStream("D:\\Test\\untitled4\\b.txt"),"GBK");
// //2、写出数据
// osw.write("你好");
// //3、释放资源
// osw.close();
}
}
3、将本地文件中的GBK文件,转成UTF-8
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
public class ConvertStreamDemo3 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader
("D:\\Test\\untitled4\\b.txt",Charset.forName("GBK"));
FileWriter fw = new FileWriter
("D:\\Test\\untitled4\\d.txt",Charset.forName("UTF-8"));
int b;
while ((b = fr.read()) != -1){
fw.write(b);
}
fw.close();
fr.close();
}
}
4、利用字节流读取文件中的数据,每次读一行,而且不能乱码
import java.io.*;
public class ConvertStreamDemo4 {
public static void main(String[] args) throws IOException {
// FileInputStream fis = new FileInputStream("D:\\Test\\untitled4\\d.txt");
// InputStreamReader isr = new InputStreamReader(fis);
// BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader
(new InputStreamReader(
new FileInputStream("D:\\Test\\untitled4\\d.txt")));
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
}
}
序列化流(对象操作输出流)/反序列化流(对象操作输入流)
- 序列化流
作用:可以把Java中的对象写到本地文件中
细节:需要让Javabean类实现Serializable接口。Serializable接口里面没有抽象方法,是一个标记型接口,一旦实现了这个接口,那么就表示当前的类可以被序列化。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo1 {
public static void main(String[] args) throws IOException {
//1、创建对象
Student stu = new Student("zhangsan",23);
//2、创建序列化流的对象
ObjectOutputStream oos = new ObjectOutputStream
(new FileOutputStream("D:\\Test\\untitled4\\a.txt"));
//3、写出数据
oos.writeObject(stu);
//4、释放资源
oos.close();
}
}
- 反序列化流
作用:可以把序列化到本地文件中的对象,读取到程序中来
import java.io.*;
public class ObjectStreamDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1、创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream
(new FileInputStream("D:\\Test\\untitled4\\a.txt"));
//2、读取数据
Object o = (Student)ois.readObject();
//3、打印对象
System.out.println(o);
//4、释放资源
ois.close();
}
}
-
细节:
1、需要在JavaBean类中加上版本号
如: private static final long serialVersionUID = 1L;
2、transient:瞬态关键字
作用:加在变量名前面,不会把当前属性序列化到本地文件当中
如:private transient String address; -
练习:将多个自定义对象序列化到文件中,但是由于对象的个数不确定,反序列化流该如何读取呢?
序列化流:
import java.io.*;
import java.util.ArrayList;
public class Test7 {
public static void main(String[] args) throws IOException {
//1、序列化多个对象
Student s1 = new Student("zhangsan",23,"北京");
Student s2 = new Student("lisi",24,"上海");
Student s3 = new Student("wangwu",25,"广州");
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
ObjectOutputStream oos = new ObjectOutputStream
(new FileOutputStream("D:\\Test\\untitled4\\a.txt"));
oos.writeObject(list);
oos.close();
}
}
反序列化流:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
public class Test8 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1、创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream
(new FileInputStream("D:\\Test\\untitled4\\a.txt"));
//2、读取数据
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student student : list) {
System.out.println(student);
}
//3、释放资源
ois.close();
}
}
打印流
-
分类:打印流一般是指:PrintStream,PrintWriter两个类
-
特点1:打印流只操作文件目的地,不操作数据源
-
特点2:特有的写出方法可以实现,数据原样写出
-
特点3:特有的写出方法,可以实现自动刷新,自动换行
打印一次数据 = 写出 + 换行 + 刷新 -
字节打印流
注意:字节流底层没有缓冲区,开不开自动刷新都一样
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class PrintStreamDemo1 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
//1、创建字节打印流的对象
PrintStream ps = new PrintStream
(new FileOutputStream("D:\\Test\\untitled4\\a.txt")
,true, Charset.forName("UTF-8"));
//2、写出数据
ps.println(97);//97
ps.print(true);//true
ps.println();
ps.printf("%s","你好");//你好
//3、释放资源
ps.close();
}
}
- 字符打印流
注意:字符流底层有缓冲区,想要自动刷新需要开启。
import java.io.*;
public class PrintStreamDemo2 {
public static void main(String[] args) throws IOException {
//1、创建字符打印流对象
PrintWriter pw = new PrintWriter
(new FileWriter("D:\\Test\\untitled4\\a.txt")
,true);
//2、写出数据
pw.println(97);
pw.print("true");
pw.println();
pw.printf("%s","你好");
//3、释放资源
pw.close();
}
}
- 打印流的应用场景
import java.io.PrintStream;
public class PrintStreamDemo3 {
public static void main(String[] args){
//获取打印流的对象,此打印流在虚拟机启动的时候,由虚拟机创建,默认指向控制台
//特殊的打印流,系统中的标准输出流,是不能关闭,在系统中是唯一的
PrintStream ps = System.out;
//调用打印流中的方法println
//写出数据,自动换行,自动刷新
ps.println("123");
//ps.close();//不能关闭,否则后面的语句将不能输出
ps.println("你好");
System.out.println("456");
}
}
解压缩流/压缩流
解压本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
- 解压缩流
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipStreamDemo1 {
public static void main(String[] args) throws IOException {
//1、创建一个File表示要解压的压缩包
File src = new File("D:\\Test2\\aaa.zip");
//2、创建一个File表示解压的目的地
File dest = new File("D:\\");
//调用方法
unzip(src, dest);
}
//定义一个方法用来解压
public static void unzip(File src, File dest) throws IOException {
//解压的本质:把压缩包里面的每一个文件或者文件夹读取出来,按照层级拷贝到目的地当中
//创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
//要先获取压缩包里面的每一个zipentry对象
//表示当前在压缩包中获取到的文件或者文件夹
ZipEntry entry;
while ((entry = zip.getNextEntry()) != null) {
System.out.println(entry);
if (entry.isDirectory()) {
//文件夹:需要在目的地的dest处创建一个同样的文件夹
File file = new File(dest,entry.toString());
file.mkdirs();
} else {
//文件:需要读取到压缩包中的文件,并把他存放到目的地dest文件夹中(按照层级目录进行存放)
FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));
int b;
while ((b = zip.read()) != -1){
//写到目的地
fos.write(b);
}
fos.close();
//表示在压缩包中的一个文件处理完毕了
zip.closeEntry();
}
}
zip.close();
}
}
- 压缩流
压缩本质:把每一个(文件/文件夹)看成ZipEntry对象放到压缩包中
压缩单个文件
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipStreamDemo2 {
public static void main(String[] args) throws IOException {
//1、创建File对象表示要压缩的文件
File src = new File("D:\\Test2\\a.txt");
//2、创建File对象表示压缩包的位置
File dest = new File("D:\\Test2\\");
//3、调用方法用来压缩
tozip(src,dest);
}
/*
作用:压缩
参数一:表示要压缩的文件
参数二:表示压缩包的位置
*/
public static void tozip(File src, File dest) throws IOException {
//1、创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream
(new FileOutputStream(new File(dest,"a.zip")));
//2、创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
ZipEntry entry = new ZipEntry("a.txt");
//3、把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//4、把src文件中的数据写到压缩包当中
FileInputStream fis = new FileInputStream(src);
int b;
while ((b = fis.read()) != -1){
zos.write(b);
}
zos.closeEntry();
zos.close();
}
}
压缩文件夹
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipStreamDemo3 {
public static void main(String[] args) throws IOException {
//1、创建File对象表示要压缩的文件夹
File src = new File("D:\\Test2\\bbb");
//2、创建File对象表示压缩包放在哪里(压缩包的父级路径)
File destParent = src.getParentFile();
//3、创建File对象表示压缩包的路径
File dest = new File(destParent,src.getName() + ".zip");
//4、创建压缩流关联的压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//5、获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
toZip(src,zos,src.getName());
//6、释放资源
zos.close();
}
/*
作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
参数一:数据源
参数二:压缩流
参数三:压缩包内部的路径
*/
public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {
//1、进入src文件夹
File[] files = src.listFiles();
//2、遍历数组
for (File file : files) {
if(file.isFile()){
//3、判断-文件,变成ZipEntry对象,放入压缩包当中
ZipEntry entry = new ZipEntry(name + "\\" + file.getName());
zos.putNextEntry(entry);
//读取文件中的数据,写到压缩包
FileInputStream fis = new FileInputStream(file);
int b;
while ((b = fis.read()) != -1){
zos.write(b);
}
fis.close();
zos.closeEntry();
}else {
//4、判断-文件夹,递归
toZip(file,zos,name + "\\" + file.getName());
}
}
}
}
常用工具包(Commons-io)
Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包。
- 作用:提高IO流的开发效率。
使用步骤:
1、在项目中创建一个文件夹:lib
2、将jar包复制粘贴到lib文件夹
3、右键点击jar包,选择Add as Library -> 点击OK
4、在类中导包使用
下载该工具包网址
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
public class CommonsIODemo1 {
public static void main(String[] args) throws IOException {
//复制文件
// File src = new File("D:\\Test\\untitled4\\a.txt");
// File dest = new File("D:\\Test\\untitled4\\copy.txt");
// FileUtils.copyFile(src,dest);
//复制文件夹
// File src = new File("D:\\Test2\\aaa");
// File dest = new File("D:\\Test2\\bbb");
// FileUtils.copyDirectoryToDirectory(src,dest);
//清空文件夹
File src = new File("D:\\Test2\\bbb");
FileUtils.cleanDirectory(src);
}
}
常用工具包(hutool)
hutool jar包下载网址
import cn.hutool.core.io.FileUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class HutoolDemo1 {
public static void main(String[] args) {
/*
//file:根据参数创建一个file对象
File file = FileUtil.file("D:\\Test2\\","aaa","bbb","a.txt");
System.out.println(file);//D:\Test2\aaa\bbb\a.txt
//touch:根据参数创建文件
File touch = FileUtil.touch(file);
System.out.println(touch);
//writeLines:把集合中的数据写出到文件中,覆盖模式
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("aaa");
File file1 = FileUtil.writeLines(list,"D:\\Test2\\a.txt","UTF-8");
System.out.println(file1);
//appendLines:把集合中的数据写出到文件中,续写模式
ArrayList<String> list1 = new ArrayList<>();
list1.add("bbb");
list1.add("bbb");
list1.add("bbb");
File file2 = FileUtil.appendLines(list,"D:\\Test2\\a.txt","UTF-8");
System.out.println(file2);
*/
//readLines:指定字符编码,把文件中的数据,读到集合中
List<String> list = FileUtil.readLines("D:\\Test2\\a.txt", "UTF-8");
System.out.println(list);
}
}
综合练习3
制造假数据(网络爬虫)
需求:在网络上爬取数据,生成随机的姓名,年龄,并写入文件中
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test9 {
public static void main(String[] args) throws IOException {
//1、定义变量记录网址
String familyNameNet = "https://hanyu.baidu.com/shici/detail?" +
"pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
String boyNameNet = "http://www.haoming8.cn/baobao/10881.html";
String girlNameNet = "http://www.haoming8.cn/baobao/7641.html";
//2、爬取数据,把网址上所有的数据拼接成一个字符串
String familyNameNetStr = webCrawler(familyNameNet);
String boyNameNetStr = webCrawler(boyNameNet);
String girlNameNetStr = webCrawler(girlNameNet);
//3、通过正则表达式,把其中符合要求的数据获取出来
ArrayList<String> familyNameTempList = getData(familyNameNetStr,"(.{4})(,|。)",1);
ArrayList<String> boyNameTempList = getData(boyNameNetStr, "([\\u4E00-\\u9FA5]{2})(、|。)", 1);
ArrayList<String> girlNameTempList = getData(girlNameNetStr, "(.. ){4}..", 0);
// System.out.println(boyNameTempList);
// System.out.println(girlNameTempList);
//4、处理数据
//familyNameTempList(姓氏)
//处理方案:把每一个姓氏拆开并添加到一个新集合当中
ArrayList<String> familyNameList = new ArrayList<>();
for (String str1 : familyNameTempList) {
for (int i = 0; i < str1.length(); i++) {
char c = str1.charAt(i);
familyNameList.add(c + "");
}
}
//boyNameTempList(男生的名字)
//处理方案:去除其中的重复元素
ArrayList<String> boyNameList = new ArrayList<>();
for (String str2 : boyNameTempList) {
if (!boyNameList.contains(str2)) {
boyNameList.add(str2);
}
}
//girlNameTempList(女生的名字)
//处理方案:把里面的每一个元素用空格进行切割,得到每一个女生的名字
ArrayList<String> girlNameList = new ArrayList<>();
for (String str3 : girlNameTempList) {
String[] arr = str3.split(" ");
for (int i = 0; i < arr.length; i++) {
girlNameList.add(arr[i]);
}
}
//5、生成数据
//姓名(唯一)-性别-年龄
ArrayList<String> list = getInfos(familyNameList, boyNameList,
girlNameList, 50, 50);
Collections.shuffle(list);
//6、写出数据
BufferedWriter bw = new BufferedWriter(
new FileWriter("D:\\Test\\untitled4\\name.txt"));
for (String str : list) {
bw.write(str);
bw.newLine();
}
bw.close();
}
/*
作用:获取男生和女生的信息:张三-男-23
形参:
参数一:装着姓氏的集合
参数二:装着男生名字的集合
参数三:装着女生名字的集合
参数四:男生的个数
参数五:女生的个数
*/
public static ArrayList<String> getInfos(ArrayList<String> familyNameList,
ArrayList<String> boyNameList,
ArrayList<String> girlNameList,
int boyCount, int girlCount){
//1、生成男生不重复的名字
HashSet<String> boyhs = new HashSet<>();
while (true){
if(boyCount == boyhs.size()){
break;
}
//随机
Collections.shuffle(familyNameList);
Collections.shuffle(boyNameList);
boyhs.add(familyNameList.get(0) + boyNameList.get(0));
}
HashSet<String> girlshs = new HashSet<>();
while (true){
if(girlCount == girlshs.size()){
break;
}
//随机
Collections.shuffle(familyNameList);
Collections.shuffle(girlNameList);
girlshs.add(familyNameList.get(0) + girlNameList.get(0));
}
ArrayList<String> list = new ArrayList<>();
//3、生成男生的信息并添加到集合当中
Random r = new Random();
//【18-27】
for (String boyName : boyhs) {
//boyName依次表示每一个男生的名字
int age = r.nextInt(10) + 18;
list.add(boyName + "-男-" + age);
}
//4、生成女生的信息并添加到集合当中
//【18-25】
for (String girlName : girlshs) {
int age = r.nextInt(8) + 18;//(0~7 +18)
list.add(girlName + "-女-" + age);
}
return list;
}
/*
作用:根据正则表达式获取字符串中的数据
参数一:完整的字符串
参数二:正则表达式
返回值:真正想要的数据
*/
private static ArrayList<String> getData(String str,String regex,int index){
//1、创建集合存放数据
ArrayList<String> list = new ArrayList<>();
//2、按照正则表达式的规则,去获取数据
Pattern pattern = Pattern.compile(regex);
//按照pattern的规则,到str当中获取数据
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
list.add(matcher.group(index));
}
return list;
}
/*
作用:从网络中爬取数据,把数据拼接成字符串返回
形参:网址
返回值:爬取到的所有数据
*/
public static String webCrawler(String net) throws IOException {
//1、定义StringBuilder拼接爬取到的数据
StringBuilder sb = new StringBuilder();
//2、创建一个URL对象
URL url = new URL(net);
//3、链接上这个网址
//细节:保证网络是畅通的,而且这个网址是可以链接上的。
URLConnection conn = url.openConnection();
//4、读取数据
InputStreamReader isr = new InputStreamReader(conn.getInputStream());
int ch;
while ((ch = isr.read()) != -1){
sb.append((char)ch);
}
//5、释放资源
isr.close();
//6、把读取到的数据返回
return sb.toString();
}
}
随机点名器
TxT文件中事先准备好一些学生信息,每个学生的信息独占一行。
要求:每次被点到的学生,再次被点到的概率在原先的基础上降低一半。
举例:80个学生,点名5次,每次都点到小A,概率变化情况如下:
第一次每人概率:1.25%。
第二次小A概率:0.625%。其他学生概率:1.2579%
第三次小A概率:0.3125%。其他学生概率:1.261867%
第四次小A概率:0.15625%。其他学生概率:1.2638449%
第五次小A概率:0.078125%。其他学生概率:1.26483389%
提示:本题的核心是带权重的随机
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
public class Test10 {
public static void main(String[] args) throws IOException {
ArrayList<Student> list = new ArrayList<>();
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\name.txt"));
String line;
while ((line = br.readLine()) != null){
String[] arr = line.split("-");
Student stu = new Student(arr[0],arr[1],
Integer.parseInt(arr[2]),Double.parseDouble(arr[3]));
list.add(stu);
}
br.close();
//2、计算权重的总和
double weight = 0;
for (Student stu : list) {
weight += stu.getWeight();
}
//3、计算每一个人的实际占比
double[] arr = new double[list.size()];
int index = 0;
for (Student stu : list) {
arr[index] = stu.getWeight() / weight;
index++;
}
//4、计算每一个人的权重占比范围
for (int i = 1; i < arr.length; i++) {
arr[i] = arr[i] + arr[i - 1];
}
//5、随机抽取
//获取0~1.0之间的随机数
double number = Math.random();
//判断number在arr中的位置
//二分查找法
//方法会返回 -插入点-1
//获取number这个数据在数组当中插入的位置
int result = -Arrays.binarySearch(arr,number) - 1;
Student stu = list.get(result);
System.out.println(stu);
//6、修改当前学生的权重
double w = stu.getWeight() / 2;
stu.setWeight(w);
//7、把集合中的数据再次写到文件中
BufferedWriter bw = new BufferedWriter
(new FileWriter("D:\\Test\\untitled4\\name.txt"));
for (Student s : list) {
bw.write(s.toString());
bw.newLine();
}
bw.close();
}
}
登录注册
需求:写一个登录小案例
步骤:
1、将正确的用户名和密码手动保存到本地的userinfo.txt文件中
2、保存格式为:username=zhangsan&password=123
3、让用户键盘录入用户名和密码
4、比较用户录入的和正确的用户名密码是否一致
5、如果一致则打印登录成功
6、如果不一致则打印失败
import java.io.*;
import java.util.Scanner;
public class Test11 {
public static void main(String[] args) throws IOException {
//1、读取正确的用户名和密码
BufferedReader br = new BufferedReader
(new FileReader("D:\\Test\\untitled4\\userinfo.txt"));
String line = br.readLine();
br.close();
String[] userInfo = line.split("&");
String[] arr1 = userInfo[0].split("=");
String[] arr2 = userInfo[1].split("=");
String rightUsername = arr1[1];
String rightPassword = arr2[1];
//2、用户键盘录入用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
//3、比较
if(rightUsername.equals(username) && rightPassword.equals(password)){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
}
}