集合
单列集合 List、Set
List
ArrayList<Integer> list = new ArrayList<> ();
// 添加元素
list.add (1);
list.add (2);
list.add (5);
list.add (6);
System.out.println (list);
// 移除 index = 1 的元素
list.remove (1);
System.out.println (list);
// 判断是否包含某个元素
boolean contains = list.contains (6);
System.out.println (contains);
// 获取元素的个数
int size = list.size ();
System.out.println (size);
// 判断是否为空
boolean isEmpty = list.isEmpty ();
System.out.println (isEmpty);
// 获取 index = 1 的元素
Integer res = list.get (1);
System.out.println (res);
// 清空 list
list.clear ();
System.out.println (list);
Set
HashSet
/**
* Set集合是一种 不允许有重复元素的集合
* 无序的
* 无索引
* 不能有重复元素
* 允许有一个null
*/
HashSet<Integer> set = new HashSet<> ();
set.add (1);
set.add (2);
set.add (null);
set.add (2);
set.add (3);
set.add (4);
// 打印Set集合
System.out.println (set);
int size = set.size ();
// 打印Set集合的大小
System.out.println (size);
boolean empty = set.isEmpty ();
// 打印Set集合是否为空
System.out.println (empty);
boolean contains = set.contains (1);
System.out.println (contains);
// 移除指定元素
set.remove (1);
System.out.println (set);
// 清空Set集合
set.clear ();
LinkedHashSet
TreeSet
/**
* 降序
*/
TreeSet<Integer> ts = new TreeSet<> ((o1, o2) -> o2 - o1);
ts.add (1);
ts.add (5);
ts.add (3);
ts.add (4);
ts.add (2);
System.out.println (ts);
for (Integer t : ts) {
System.out.print (t+" ");
}
两种 排序方式
public class User implements Comparable<User> {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "User{name = " + name + ", age = " + age + "}";
}
@Override
public int compareTo(User o) {
// 按照年龄 升序
return this.getAge () - o.getAge ();
}
}
TreeSet<User> ts = new TreeSet<> ();
ts.add (new User ("zhangsan",18));
ts.add (new User ("lisi",19));
ts.add (new User ("wangwu",20));
for (User user : ts) {
System.out.println (user);
}
// 可以使用 Lambda表达式简化
TreeSet<User> ts = new TreeSet<> (new Comparator<User> () {
@Override
public int compare(User u1, User u2) {
// 降序
return u2.getAge () - u1.getAge ();
}
});
ts.add (new User ("zhangsan", 18));
ts.add (new User ("lisi", 19));
ts.add (new User ("wangwu", 20));
for (User user : ts) {
System.out.println (user);
}
双列集合 Map
HashMap
键 存 自定义对象需重写
值 不需要
// HashMap 无序
// 可存储自定义对象
HashMap<String, Integer> map = new HashMap<> ();
// 添加元素 put
map.put ("小米", 2000);
map.put ("华为", 3000);
map.put ("苹果", 5000);
System.out.println (map);
/**
* 键 不存在,直接添加键值对
* 键 存在,覆盖
*/
map.put ("苹果", 6000);
System.out.println (map);
// putIfAbsent 不存在键时,才添加
map.putIfAbsent ("小米", 1000);
System.out.println (map);
// 获取键对应的值,不存在 返回null
Integer huawei = map.get ("华为");
System.out.println ("华为价格:" + huawei);
Integer huaweiS = map.get ("华为s");
System.out.println ("华为s价格:" + huaweiS);
// 获取键对应的值,不存在 返回默认值
Integer huaweiS2 = map.getOrDefault ("华为s", 9999);
System.out.println ("华为s价格:" + huaweiS2);
System.out.println ("=========================");
/**
* 获取 键值对集合 来遍历map
*/
Set<Map.Entry<String, Integer>> entries = map.entrySet ();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey ();
Integer value = entry.getValue ();
System.out.println (key + " " + value);
}
System.out.println ("=========================");
/**
* 获取所有的键
*/
Set<String> keySet = map.keySet ();
for (String key : keySet) {
Integer val = map.get (key);
System.out.println (key + " " + val);
}
System.out.println ("=========================");
/**
* Lambda表达式 遍历map
*/
map.forEach ((k, v) -> {
System.out.println (k + " " + v);
});
System.out.println ("=========================");
// 删除键值对,返回值是 键对应的值
Integer val = map.remove ("小米");
System.out.println (val);
System.out.println (map);
System.out.println ("=========================");
// 判断键是否存在
boolean keyHua = map.containsKey ("华为");
boolean keyXm = map.containsKey ("小米");
System.out.println ("华为:" + keyHua + " " + "小米:" + keyXm);
System.out.println ("=========================");
// 判断值是否存在
boolean containsValue = map.containsValue (1000);
System.out.println ("值是否存在:" + containsValue);
System.out.println ("=========================");
// 判断是否为空
boolean empty = map.isEmpty ();
System.out.println ("map为空:" + empty);
System.out.println ("=========================");
// 集合大小
int size = map.size ();
System.out.println ("集合大小:" + size);
System.out.println ("=========================");
// 清空集合
map.clear ();
HashMap 练习
/**
* 80 名学生,进行秋游
* 四个景点
* A B C D
* 每个学生只能选择一个景点
* 统计最终哪个景点想去的人数最多
*/
String[] arr = {"A", "B", "C", "D"};
Random r = new Random ();
HashMap<String, Integer> map = new HashMap<> ();
for (int i = 0; i < 80; i++) {
int idx = r.nextInt (4);
// 获取随机景点
String name = arr[idx];
// 在原有的基础上+1
map.put (name, map.getOrDefault (name, 0) + 1);
}
Set<String> keySet = map.keySet ();
// 记录结果
int max = 0;
String name = "";
for (String key : keySet) {
Integer val = map.get (key);
if (val > max) {
max = val;
name = key;
}
}
System.out.println (name + " " + max);
System.out.println (map);
LinkedHashMap
LinkedHashMap<String , Integer> map = new LinkedHashMap<> ();
map.put ("c", 1);
map.put ("a", 2);
map.put ("b", 3);
map.put ("d", 4);
System.out.println (map);
TreeMap
/**
* 按照字符串长度 降序排序
*/
TreeMap<String, Integer> map = new TreeMap<> ((o1, o2) -> o2.length () - o1.length ());
map.put ("a", 1);
map.put ("dd", 4);
map.put ("edw", 5);
map.put ("dwda", 3);
System.out.println (map);
练习1 不重复的随机点名
/**
* 班级里有5个学生
* 要求:
* 被点到的学生,不能再被点到
* 如果所有的学生都被点到了,需要重新开启第二轮点名
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ArrayList<String> list = new ArrayList<> ();
Collections.addAll (list, "张三", "李四", "王五", "赵六", "钱七");
// 记录被点到的学生
ArrayList<String> list1 = new ArrayList<> ();
// 开启点名,10次
Random random = new Random ();
for (int i = 0; i < 10; i++) {
// 随机获取一个下标,范围是[0,集合的长度)
// size 会随着集合的变化而变化
int index = random.nextInt (list.size ());
// 根据下标,从集合中删除一个元素,返回被删除的元素
// 根据元素,删除集合中的元素,返回删除是否成功 boolean
String s = list.remove (index);
list1.add (s);
System.out.println (s);
// 如果集合中没有元素了,需要重新开启第二轮点名
if (list.size () == 0) {
list.addAll (list1);
list1.clear ();
System.out.println ("---------------------------");
}
}
}
练习2 集合嵌套
public static void main(String[] args) throws Exception {
test1 ();
}
/**
* 将省份和市 使用Map集合存储
* 遍历Map集合
*/
private static void test1() {
// 值还是一个 List
Map<String, List<String>> map = new HashMap<String, List<String>> ();
ArrayList<String> list1 = new ArrayList<> ();
Collections.addAll (list1, "石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市");
map.put ("河北省", list1);
ArrayList<String> list2 = new ArrayList<> ();
Collections.addAll (list2, "太原市", "大同市", "阳泉市", "长治市", "晋城市");
map.put ("山西省", list2);
ArrayList<String> list3 = new ArrayList<> ();
Collections.addAll (list3, "沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市");
map.put ("辽宁省", list3);
//遍历map集合,获取键值对的方式
for (Map.Entry<String, List<String>> entry : map.entrySet ()) {
String key = entry.getKey ();
String val = "";
List<String> value = entry.getValue ();
for (int i = 0; i < value.size (); i++) {
val += value.get (i);
// 如果是最后一个元素就不加逗号
// 不加逗号很难直接实现,转为 不是最后一个元素就加逗号
if (i != value.size () - 1) {
val += ",";
}
}
System.out.println (key + "=" + val);
}
}
File
创建对象
/**
* \: 表示转义字符
* \\: 表示一个普通的反斜杠
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// 通过文件路径获取文件对象
String path = "C:\\Users\\Administrator\\Desktop\\a.txt";
File file1 = new File (path);
System.out.println (file1);
// 通过父路径和子路径获取文件对象
String parent = "C:\\Users\\Administrator\\Desktop";
String child = "a.txt";
File file2 = new File (parent, child);
System.out.println (file2);
// \\: 表示一个普通的反斜杠
// \: 表示转义字符
File file3 = new File (parent + "\\" + child);
System.out.println (file3);
file1.delete ();
}
成员方法
判断、获取
// 通过文件路径获取文件对象
String path = "C:\\Users\\Administrator\\Desktop\\a.txt";
File file1 = new File (path);
boolean exists = file1.exists ();
if (exists) {
System.out.println ("文件存在");
// 文件大小
System.out.println (file1.length ());
// 文件名称
System.out.println (file1.getName ());
// 文件路径
System.out.println (file1.getPath ());
// 绝对路径
System.out.println (file1.getAbsolutePath ());
// 最后修改时间
long lastModified = file1.lastModified ();
Date date = new Date (lastModified);
System.out.println (date);
// 是否是文件
System.out.println (file1.isFile ());
// 是否是文件夹
System.out.println (file1.isDirectory ());
// 是否隐藏
System.out.println (file1.isHidden ());
// 是否可读
System.out.println (file1.canRead ());
// 是否可写
System.out.println (file1.canWrite ());
// 是否可执行
System.out.println (file1.canExecute ());
// 父级路径
System.out.println (file1.getParent ());
}
创建、删除
public static void main(String[] args) throws Exception {
// 通过文件路径获取文件对象
String path = "C:\\Users\\Administrator\\Desktop\\b.txt";
File file1 = new File (path);
// 创建文件,需要父级目录存在,否则创建失败
/**
* Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
*/
boolean newFile = file1.createNewFile ();
System.out.println (newFile);
System.out.println ("--------------");
/**
* 创建多级目录
* mkdirs:创建多级目录
* mkdir:创建一级目录
*/
boolean mkdirs = new File ("D:\\a\\b\\c").mkdirs ();
System.out.println (mkdirs);
/**
* 删除文件或者文件夹
* delete:删除文件或者文件夹
* 注意:
* 1.如果删除的是文件夹,那么文件夹必须是空的,否则删除失败
* 2.如果删除的是文件,那么文件必须 存在,否则删除失败
* 3.如果删除的是文件夹,那么文件夹必须存在,否则删除失败
*
*/
boolean delete = file1.delete ();
System.out.println (delete);
System.out.println ("--------------");
deleteDir (new File ("D:\\a"));
}
/**
* 递归删除文件夹
*/
public static void deleteDir(File dir) {
// 获取文件夹下的 所有文件或者文件夹
File[] files = dir.listFiles ();
// 遍历文件夹下的所有文件或者文件夹
for (File file : files) {
// 判断当前遍历的是文件还是文件夹
if (file.isFile ()) {
// 如果是文件,直接删除
file.delete ();
} else {
// 如果是文件夹,递归删除
deleteDir (file);
}
}
// 删除文件夹
dir.delete ();
}
练习
查找一个文件夹中,有没有avi文件
public static void main(String[] args) throws Exception {
File file = new File ("D:\\aaa");
boolean haveAvi = haveAvi (file);
System.out.println (haveAvi);
}
/**
* 查找一个文件夹中,有没有avi文件
*
* @param f
* @return
*/
public static boolean haveAvi(File f) {
// 获取文件列表
File[] files = f.listFiles ();
for (File file : files) {
// 判断是否是文件
// 判断是否是avi文件
if (file.isFile () && file.getName ().endsWith (".avi")) {
return true;
}
}
// 如果没有找到,返回false
return false;
}
统计一个文件中每种文件的个数,并且打印(考虑子文件夹)
/**
* 统计一个文件中每种文件的个数,并且打印(考虑子文件夹)
* 打印格式如下:
* txt:3个
* doc:5个
* avi:2个
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// 创建一个文件对象
File f = new File ("D:\\aaa");
// 调用方法
int num = countFile (f, ".txt");
System.out.println (".txt" + "文件有" + num + "个");
}
private static int countFile(File f, String suffix) {
File[] files = f.listFiles ();
int sum = 0;
// 遍历文件列表
for (File file : files) {
// 判断是否是文件,且是否是指定的文件类型
if (file.isFile () && file.getName ().endsWith (suffix)) {
sum++;
}
// 判断是否是文件夹
else if (file.isDirectory ()) {
sum = sum + countFile (file, suffix);
}
}
return sum;
}
IO 流
介绍
字节输入、输出流
每次操作 一个字节
字节输出流
/**
* 字节输出流,写一段文字到指定的文件中
* 1.创建字节输出流对象
* 2.写数据
* 3.释放资源
*/
FileOutputStream fos = new FileOutputStream (new File ("D:\\aaa\\a.txt"));
// append为true,追加写入,默认false,覆盖写入
FileOutputStream fos2 = new FileOutputStream ("D:\\aaa\\a.txt", true);
// 写数据,写一个字节
fos.write (65);
byte[] data = {65, 66, 67};
// 写数据,写一个字节数组
fos.write (data);
// 换行
fos.write ("\r\n".getBytes ());
fos.write ("一切很好".getBytes ());
// 关闭流,释放资源
fos.close ();
字节输入流
public static void main(String[] args) throws IOException {
/**
* 字节输入流 循环读取数据
*/
FileInputStream fis = new FileInputStream ("D:\\aaa\\a.txt");
int b;
/**
* read读取一次,指针会移动一次
*/
while ((b = fis.read ()) != -1) {
System.out.println ((char) b);
}
fis.close ();
}
文件拷贝
/**
* 文件拷贝
*/
FileInputStream fis = new FileInputStream ("D:\\aaa\\a.txt");
FileOutputStream fos = new FileOutputStream ("D:\\aaa\\b.txt");
int b;
while ((b = fis.read ()) != -1) {
fos.write (b);
}
fos.close ();
fis.close ();
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
/**
* 文件拷贝
*/
fis = new FileInputStream ("D:\\aaa\\a.txt");
fos = new FileOutputStream ("D:\\aaa\\b.txt");
int len;
byte[] data = new byte[1024];
// read 读到data 中,返回的是读到的字节数
while ((len = fis.read (data)) != -1) {
// write 写入 data 中,从0 开始,写入 len 个字节
fos.write (data, 0, len);
}
} catch (IOException e) {
throw new RuntimeException (e);
}
/**
* 关闭流
* finally 一定会执行
*/
finally {
if (fis != null) {
fis.close ();
}
if (fos != null) {
fos.close ();
}
}
}
字符集编码
String s = "爱你哟";
byte[] bytes = s.getBytes (); // 可以指定编码方式
System.out.println (Arrays.toString (bytes));
字符输入流、输出流
FileReader
FileReader fr = new FileReader ("D:\\aaa\\a.txt");
int ch;
while ((ch = fr.read ()) != -1)
{
System.out.println (ch);
}
fr.close ();
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader ("D:\\aaa\\a.txt");
int len;
char[] c = new char[1024];
// 读取数据,并将数据存储在数组中
// fr.read(c)返回的是读取到的有效字符个数
// 将读取、解码、强转三步合并
while ((len = fr.read (c)) != -1) {
// 打印数组中的数据,从0索引到len索引
System.out.println (new String (c, 0, len));
}
fr.close ();
}
FileReader fr = new FileReader ("D:\\aaa\\a.txt");
FileWriter fw = new FileWriter ("D:\\aaa\\b.txt");
int len;
char[] c = new char[1024];
// 读取文件,返回的是读取的字符个数
while ((len = fr.read (c)) != -1) {
fw.write (c,0,len);
}
fw.close ();
fr.close ();
FileReader fr = new FileReader ("D:\\aaa\\a.txt");
fr.read (); // 将文件的数据放到缓冲区中
FileWriter fw = new FileWriter ("D:\\aaa\\a.txt"); // append默认false,清空文件内容,true不清空
int c;
while ((c = fr.read ()) != -1) {
// 只能读取 缓冲区中的数据
// 文件中 剩余的数据无法读取
System.out.println ((char) c);
}
fw.close ();
fr.close ();
FileWriter
// append默认false,清空文件内容,true不清空
FileWriter fw = new FileWriter ("a.txt");
// 写入数据
char[] chars = {'a', 'b', 'c', '我'};
fw.write (chars);
// 在关闭之前,先刷新数据到文件中
fw.close ();
// append默认false,清空文件内容,true不清空
FileWriter fw = new FileWriter ("a.txt");
fw.write ("我的同学各个都很优秀");
fw.write ("说话好听");
fw.write ("学习刻苦");
// 刷新,将内存中的数据写入到文件中
fw.flush ();
fw.write ("成绩优秀");
fw.write ("是个好同学");
// 在关闭之前,先刷新数据到文件中
fw.close ();
练习
字节、字符缓冲流
字节 缓冲流
缓冲流 提高 读写效率
/**
* 缓冲流提高读写效率
*/
BufferedInputStream bis = new BufferedInputStream (new FileInputStream ("D:\\aaa\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream ("D:\\aaa\\b.txt"));
byte[] bytes = new byte[1024];
int len = 0;
// 往b.txt中写入a.txt中的内容
while ((len = bis.read (bytes)) != -1) {
bos.write (bytes, 0, len);
}
bis.close ();
bos.close ();
内存运算速度 更快
字符 缓冲流
/**
* 缓冲流提高读写效率 readLine
*
*/
BufferedReader br = new BufferedReader (new FileReader ("D:\\aaa\\a.txt"));
// 一次读取一行
String s1 = br.readLine ();
System.out.println (s1);
br.close ();
/**
* 缓冲流提高读写效率 newLine
*
*/
BufferedWriter bw = new BufferedWriter (new FileWriter ("D:\\aaa\\a.txt", true));
bw.write ("你微笑的时候,我也微笑");
// 换行
bw.newLine ();
bw.write ("你哭的时候,我也哭");
bw.newLine ();
bw.write ("你生气的时候,我也生气");
bw.close ();
public static void main(String[] args) throws IOException {
/**
* 从这个文件读取出师表
*/
BufferedReader br = new BufferedReader (new FileReader ("D:\\aaa\\csb.txt"));
// 一次读取一行
String s;
ArrayList<String> list = new ArrayList<> ();
while ((s = br.readLine ()) != null) {
// 将读取到的每一行添加到集合中
list.add (s);
}
// 对集合进行排序
Collections.sort (list, (o1, o2) -> {
int i1 = Integer.parseInt (o1.split ("\\.")[0]);
int i2 = Integer.parseInt (o2.split ("\\.")[0]);
// 升序
return i1 - i2;
});
BufferedWriter bw = new BufferedWriter (new FileWriter ("D:\\aaa\\dest.txt"));
for (String data : list) {
// 写入
bw.write (data);
// 换行
bw.newLine ();
// 刷新
bw.flush ();
}
bw.close ();
br.close ();
}
序列化、反序列化流
序列化流
/**
* 将一个对象写到本地文件中
*/
User user = new User ("张三", 18);
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("a.txt"));
// 将对象写到本地文件中
oos.writeObject (user);
// 释放资源
oos.close ();
反序列化 流
ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("a.txt"));
User o = (User) ois.readObject ();
System.out.println (o);
ois.close ();
使用细节
/**
* Serializable接口
* 表示可序列化的对象
*/
public class User implements Serializable {
// 序列化版本号,固定好后,就不会再发生 序列化版本号不匹配的错误
private static final long serialVersionUID = 1L;
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "User{name = " + name + ", age = " + age + "}";
}
}
// transient 表示该属性不会被序列化
private transient String address;
综合练习
/**
* 将多个自定义对象 序列化到一个文件中,对象个数不确定,如何操作?
*/
// 创建数组
List<User> list = new ArrayList<> ();
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("a.txt"));
list.add (new User ("张三", 18));
list.add (new User ("李四", 19));
list.add (new User ("王五", 20));
// 序列化
oos.writeObject (list);
oos.close ();
ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("a.txt"));
// 读取对象
List<User> list = (List<User>) ois.readObject ();
// 遍历
for (User user : list) {
System.out.println (user);
}
ois.close ();
解压缩流
压缩
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZIPCompress {
public static void main(String[] args) {
String sourceFile = "input.txt"; // 要压缩的文件
String zipFile = "compressed.zip"; // 压缩后的 ZIP 文件
try (FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zipOS = new ZipOutputStream(fos)) {
FileInputStream fis = new FileInputStream(sourceFile);
ZipEntry zipEntry = new ZipEntry(sourceFile);
zipOS.putNextEntry(zipEntry);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
zipOS.write(buffer, 0, len);
}
zipOS.closeEntry();
fis.close();
System.out.println("文件压缩完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
ZipOutputStream
用于将文件压缩为 ZIP 格式。我们通过 putNextEntry()
创建新的 ZIP 条目,并将每个文件的内容写入 ZIP 文件中。
closeEntry()
用于关闭当前 ZIP 条目,表明该文件的压缩已完成。
解压
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZIPDecompress {
public static void main(String[] args) {
String zipFile = "compressed.zip"; // 压缩文件
String outputDir = "output/"; // 解压后的输出目录
try (FileInputStream fis = new FileInputStream(zipFile);
ZipInputStream zis = new ZipInputStream(fis)) {
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
String outputFile = outputDir + zipEntry.getName();
FileOutputStream fos = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int len;
while ((len = zis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
fos.close();
zis.closeEntry();
zipEntry = zis.getNextEntry();
}
System.out.println("文件解压完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
ZipInputStream
允许我们解压 ZIP 文件中的多个条目。我们通过getNextEntry()
获取 ZIP 文件中的每个条目,并将解压后的内容输出到指定目录
。
解压缩流与压缩流的应用场景:
- 文件压缩:当需要
减少文件大小
以便传输或存储时,可以使用压缩流对文件进行压缩,常用于日志文件压缩、备份等场景。 - 网络传输:在网络传输中,压缩流能有效减少数据体积,缩短传输时间,特别适用于需要大量数据传输的应用。
- 数据备份:压缩流可以用来创建备份文件,特别是将多个文件或目录压缩成一个 ZIP 文件,方便存储和分发。
常用 IO工具包
Commons-io
File src = new File ("D:\\aaa\\a.txt");
File dest = new File("D:\\aaa\\b.txt");
FileUtils.copyFile(src,dest);
Hutool 工具包
File file = FileUtil.file ("D:\\aaa\\c.txt");
file.createNewFile ();
ArrayList<String> list = new ArrayList<> ();
Collections.addAll (list,"我们不一样","你很牛啊","我不服");
FileUtil.writeLines (list,"D:\\aaa\\a.txt","utf-8",false);
ArrayList<String> list = new ArrayList<> ();
ArrayList<String> strings = FileUtil.readLines ("D:\\aaa\\a.txt", "utf-8", list);
for (String s : strings) {
System.out.print (s+" ");
}
多线程&JUC
线程
new Thread (() -> {
int count=1;
for (int i = 0; i < 100; i++) {
String name = Thread.currentThread ().getName ();
System.out.println (name+" hello world " +(count++));
}
}).start ();
new Thread (() -> {
int count=1;
for (int i = 0; i < 100; i++) {
String name = Thread.currentThread ().getName ();
System.out.println (name+" hello world " +(count++));
}
}).start ();
Thread 类常见成员方法
线程的生命周期、安全问题
public class Ticket
{
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Ticket(int num) {
this.num = num;
}
private int num;
public void sale(String window) {
while (num > 0) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
System.out.println (window + "卖出了第" + num-- + "张票");
}
}
}
/**
* 某电影院共有100张票,现有3个窗口卖票
*/
Ticket ticket = new Ticket (100);
new Thread (
() -> {
for (int i = 0; i < 1000; i++) {
ticket.sale ("窗口1");
}
}
).start ();
new Thread (
() -> {
for (int i = 0; i < 1000; i++) {
ticket.sale ("窗口2");
}
}
).start ();
new Thread (
() -> {
for (int i = 0; i < 1000; i++) {
ticket.sale ("窗口3");
}
}
).start ();
超卖, 超过了库存
解决超卖
public void sale(String window) {
/**
* 出现线程安全问题
* 解决方式:
* 1、同步代码块
* 2、同步方法
* 3、lock锁
*/
synchronized (this) {
if (num > 0) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
System.out.println (window + "卖出了第" + num-- + "张票");
}
}
}
同步代码块
/**
* 出现线程安全问题
* 解决方式:
* 1、同步代码块
* 2、同步方法
* 3、lock锁
*/
synchronized (this) {
if (num > 0) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
System.out.println (window + "卖出了第" + num-- + "张票");
}
}
锁
public void sale(String window) {
ReentrantLock lock = new ReentrantLock ();
lock.lock ();
try {
if (num > 0) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
System.out.println (window + "卖出了第" + num-- + "张票");
}
} finally {
lock.unlock ();
}
}
为什么 还是出现了超卖?
每次调用该方法都会创建一个锁~每次锁对象不同
解决:将锁 置为 成员变量
// 每次 锁对象就这一个~
private ReentrantLock lock = new ReentrantLock ();
public void sale(String window) {
lock.lock ();
try {
if (num > 0) {
try {
Thread.sleep (100);
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
System.out.println (window + "卖出了第" + num-- + "张票");
}
} finally {
lock.unlock ();
}
}
等待唤醒机制 wait / notify
线程 操作 资源类
桌子:
public class Desk {
// 总个数 10
public static int count = 10;
// 食物标志《0 没有食物 1有食物》
public static int foodFlag = 0;
// 同步锁
public static Object lock = new Object ();
}
厨师:
public class Cook extends Thread {
/**
* 1、循环
* 2、同步代码块
* 3、判断数据是否到了末尾(到了末尾,就不再循环)
* 4、判断数据是否到了末尾(没有到末尾,执行代码核心逻辑)
*/
@Override
public void run() {
// 不停的循环
while (true) {
// 每次只允许一个线程进入
synchronized (Desk.lock) {
Desk.foodFlag = 1;// 有食物
// 当食物数量大于 10的时候,就不再生产
if (Desk.count >= 10) {
try {
Desk.lock.wait (); // 食物数量大于 10的时候,就不再生产
} catch (InterruptedException e) {
throw new RuntimeException (e);
}
} else {
System.out.println (getName () + "正在生产第" + (++Desk.count) + "个汉堡");
}
}
}
}
}
吃饭者:
public class Foodies extends Thread {
/**
* 1、循环
* 2、同步代码块
* 3、判断数据是否到了末尾(到了末尾,就不再循环)
* 4、判断数据是否到了末尾(没有到末尾,执行代码核心逻辑)
*/
@Override
public void run() {
// 不停的循环
while (true) {
// 每次只允许一个线程进入
synchronized (Desk.lock) {
if (Desk.count <= 0) {
Desk.foodFlag = 0;// 没有食物
Desk.lock.notifyAll (); // 唤醒所有线程
} else {
System.out.println (getName () + "正在吃第" + (Desk.count--) + "个汉堡");
}
}
}
}
}
综合练习
抢红包
public class GetRed extends Thread {
// static 属于类
private static BigDecimal money = new BigDecimal ("100");
private static int count = 3;
private static final BigDecimal MIN = new BigDecimal ("0.01");
private String name;
public GetRed(String name) {
super (name);
}
/**
* 微信中的抢红包
* 100 块,分成三个包,现有 3人去抢
* 红包是共享数据
* 最小中奖金额 0.01
*/
@Override
public void run() {
synchronized (GetRed.class) {
if (count == 0) {
// 抢完了
System.out.println (getName () + "没抢到红包");
} else {
BigDecimal prize;
// 最后一个红包
if (count == 1) {
prize = money;
} else {
// 不是最后一个红包
// 因为每次抽奖金额最低是 0.01 ,所以每次抽奖的最大值是剩余红包金额 - 0.01 * 剩余红包个数
prize = BigDecimal.valueOf (Math.random () * money.floatValue () - (count - 1) * MIN.floatValue ());
}
prize = prize.setScale (2, RoundingMode.HALF_UP);
money = money.subtract (prize);
count--;
System.out.println (getName () + "抢到红包" + prize + "元");
}
}
}
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
new GetRed ("张三").start ();
new GetRed ("李四").start ();
new GetRed ("王五").start ();
}
线程池
业务开发使用 :自定义线程池,方便使用
// 最大线程数
System.out.println (Runtime.getRuntime ().availableProcessors ());
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor (
3, // 核心线程数
6, // 最大线程数
10, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<> (100), // 阻塞队列
new ThreadPoolExecutor.AbortPolicy () // 拒绝策略
);
volatile
保证多线程变量的 可见性