io流
io流的概述
io流的体系
字节输出流基本用法
package mybytestream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
演示:宁节输出流FileOutputStream
实现需求:写出一段文字到本地文件中。(暂时不写中文)
实现步骤:
创建对象
写出数据
释放资源
*/
//1.创建对象
//1.创建对象
//写出 输出流 OutputStream
//本地文件
FileOutputStream fos=new FileOutputStream("..\\myio\\a.txt");
//2.写出数据
fos.write(97);
//3.释放数据
fos.close();
}
}
FileOutputStream写数据的3种方式
package mybytestream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
void write(int b)一次写一个字节数据
void write(byte[] b)一次写一个字节数组数据
void write(byte[]b, int off, int len)一次写一个字节数组的部分数据
参数一:
数组
参数二:
起始索引
参数三:
个数
*/
//1.创建对象
FileOutputStream fos=new FileOutputStream("..\\myio\\a.txt");
//2.写出数据
//fos.write(97);//a
//fos.write(98);//b
byte[] bytes={97,98,99,100,101};
//fos.write(bytes);//abcde
fos.write(bytes,1,2);//bc
//3.释放资源
fos.close();;
}
}
换行和续写
package mybytestream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDem03 {
public static void main(String[] args) throws IOException {
/*
换行写:
再次写出一个换行符就可以了
windows:\r\n
Linux:\n
Mac:\r
细节:
在windows操作系统当中,java对回车换行进行了优化。
虽然完整的是\r\n,但是我们写其中一个\r或者\n,
java也可以实现换行,因为java在底层会补全。
建议:
不要省略,还是写全了。
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
*/
//1.创建对象
FileOutputStream fos=new FileOutputStream("..\\myio\\a.txt",true);
//2.写出数据
String str1="阳雨婵";
byte[] bytes1=str1.getBytes();
fos.write(bytes1);
//再次写出一个换行符就可以了
String wrap="\r\n";
byte[] bytes2=wrap.getBytes();
fos.write(bytes2);
String str3="666";
byte[] bytes3=str3.getBytes();
fos.write(bytes3);
//3.释放资源
fos.close();
}
}
FileInputStream字节输入流的基本用法
package mybytestream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ByteStreamDemo4 {
public static void main(String[] args) throws IOException {
/*
演示:字节输入流FileInputStream
实现需求:读取文件中的数据。(暂时不写中文)
实现步骤:
创建对象
读取数据
释放资源
*/
//1.创建对象
FileInputStream fis=new FileInputStream("..\\myio\\a.txt");
//2.读取数据
for (int i = 0; i < 5; i++) {
int b=fis.read();
System.out.println((char)b);
}
//3.释放资源
fis.close();
}
}
所需要注意的细节
循环读取
package mybytestream;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo5 {
public static void main(String[] args) throws IOException {
/*
字节输入流循环读取
*/
//1.创建对象
FileInputStream fis=new FileInputStream("..\\myio\\a.txt");
//2.循环读取
int b;
while((b=fis.read())!=-1){
System.out.println((char) b);
}
//3.释放资源
fis.close();
/*
read:表示读取数据,而且是读取一个数据就移动一次指针
FileInputStream fis=new FileInputStream("..\\myio\\a.txt");
//2.循环读取
while((fis.read())!=-1){
System.out.println(fis.read());
}
//3.释放资源
fis.close();
*/
}
}
文件拷贝基本代码
package mybytestream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo6 {
public static void main(String[] args) throws IOException {
/*
练习:
文件拷贝
注意:
选择一个比较小的文件,不要太大
*/
//q.创建对象
FileInputStream fis=new FileInputStream("D:\\cd");
FileOutputStream fos=new FileOutputStream("..\\myio\\copy");
//2.拷贝
//核心思想:边读边想
int b;
while ((b=fis.read())!=-1){
fos.write(b);
}
//释放资源
//规则:最先开的最后关闭
fos.close();;
fis.close();;
}
}
字节流一次读取多个字节
package mybytestream;
import java.io.FileInputStream;
import java.io.IOException;
public class ByteStreamDemo7 {
public static void main(String[] args) throws IOException {
/*
public int read(byte[] buffer) 一次读一个字节数组数据
*/
//1.创建对象
FileInputStream fis=new FileInputStream("..\\myio\\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
int len2=fis.read(bytes);
System.out.println(len2);//2
String str2=new String(bytes,0,len2);
System.out.println(str2);//cd
int len3=fis.read(bytes);
System.out.println(len3);//1
String str3=new String(bytes,0,len3);
System.out.println(str3);//e
//3.释放数据
fis.close();
}
}
用此方法进行文件拷贝
package mybytestream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteStreamDemo8 {
public static void main(String[] args) throws IOException {
/*
练习:文件拷贝(27.0MB)
*/
long start=System.currentTimeMillis();
//1.创建对象
FileInputStream fis=new FileInputStream("D:\\腾讯会议\\WeMeet\\3.31.2.441\\wemeet_app_components.dll");
FileOutputStream fos=new FileOutputStream("..\\myio\\copy.dll");
//2.拷贝
int len;
byte[] bytes=new byte[1024*1024*5];
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//3.释放资源
fos.close();
fis.close();
long end=System.currentTimeMillis();
System.out.println(end-start);//40ms
}
}
io流中的异常处理
finally中的语句一定会执行,所有可以将释放资源的代码用finally控制,确保资源能正常释放。
字符集详解
(GBK)
在计算机中,任意数据都是以二进制的形式来存储的
存储英文,一个字节足以
核心1:GBK中,一个英文字母一个字节,二进制第一位是0
核心2:GBK中,一个中文汉字两个字节,二进制第一位是1
(Unicode)
UTF-8不是字符集,是Unicode字符集的一种编码方式。
为什么会有乱码
原因1:读取数据时未读完整个汉字
原因2:编码和解码的方式不统一
拷贝时是一个字节一个字节进行拷贝的,所有使用字节流拷贝也不会出现乱码
java中的编码和解码
package mycharset;
import java.io.UnsupportedEncodingException;
import java.sql.SQLOutput;
import java.util.Arrays;
public class CharSetDemo1 {
public static void main(String[] args) throws UnsupportedEncodingException {
/*
Java中编码的方法
public byte[] getBytes()使用默认方式进行编码
public byte[] getBytes(string charsetName) 使用指定方式进行编码
Java中解码的方法
String(byte[] bytes)使用默认方式进行解码
String(byte[l bytes, string charsetName)使用指定方式进行解码
*/
//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(bytes1,"GBK");
System.out.println(str3);
}
}
字符流
FIleReader字符输入流
空参read方法详解
package mycharstream1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
第一步:创建对象
public FileReader(File file)创建字符输入流关联本地文件
public FileReader(string pathname)创建字符输入流关联本地文件
第二步:读取数据
public int read()读取数据,读到末尾返回-1
public int read(char[] buffer)读取多个数据,读到末尾返回-1
第三步:释放资源
public void close()释放资源/关流
*/
//1创建对象并关联本地文件
FileReader fr=new FileReader(("..\\myio\\a.txt"));
//2.读取数据 read()
//字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
//如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节
//read()细节:
//1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
//2.在读取之后,方法的底层还会进行解码并转成十进制。
//最终把这个十进制作为返回值
//这个十进制的数据也表示在字符集上的数字
//英文:文件里面二进制数据 0118 0001
//read方法进行读取,解码并转成十进制97
//中义:文件里面的二进制数据 11100110 10110801 10001001
//read方法进行读取,解码并转成十进制27721
//我想看到中文汉字,就是把这些十进制数据,再进行强转就可以了
int ch;
while((ch=fr.read())!=-1){
System.out.print((char) ch);
}
}
}
有参read方法详解
package mycharstream1;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
第一步:创建对象
public FileReader(File file)创建字符输入流关联本地文件
public FileReader(string pathname)创建字符输入流关联本地文件
第二步:读取数据
public int read()读取数据,读到末尾返回-1
public int read(char[] buffer)读取多个数据,读到末尾返回-1
第三步:释放资源
public void close()释放资源/关流
*/
//1.创建对象
FileReader fr = new FileReader("..\\myio\\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字符输出流
package mycharstream1;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
/*
第一步:创建对象
public FileWriter(File file)创建字符输出流关联本地文件
public FileWriter(string pathname)创建字符输出流关联本地文件
public FileWriter(File file, boolean append)创建字符输出流关联本地文件,续写
public FileWriter(string pathname, boolean append)创建字符输出流关联本地文件,续写
第二步:读取数据
void write(int c)写出一个字符
void write(string str)写出一个字符串
void write(string str, int off, int len)写出一个字符串的一部分
void write(char[] cbuf)写出一个字符数组
void write(char[] cbuf, int off, int len)写出字符数组的一部分
第三步:释放资源
public void close()释放资源/关流
'我' 25105
*/
FileWriter fw=new FileWriter("..\\myio\\a.txt",true);
//fw.write(25105);
//fw.write("你好威啊???");
char[] chars={'a','b','c','我'};
fw.write(chars);
fw.close();
}
}
字符流原理解析
练习
1.拷贝
package Test;
import java.io.*;
import java.lang.reflect.Field;
public class Test1 {
public static void main(String[] args) throws IOException {
File src=new File("D:\\应用\\Inno Setup 5\\Languages");
File dest=new File("D:\\aaa\\dest");
copydir(src,dest);
}
public static void copydir(File src,File dest) throws IOException {
dest.mkdirs();
File[] files=src.listFiles();
for(File file:files){
if(file.isFile()){
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{
copydir(file,new File(dest,file.getName()));
}
}
}
}
2.文件加密
package Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test2 {
public static void main(String[] args) throws IOException {
/*
异或
两边相同:false
两边不同:true
一个数异或两次同一个数会得到他本身
*/
//创建对象关联原始文件
FileInputStream fis=new FileInputStream("..\\myio\\ency.jpg");
//创建对象管理加密文件
FileOutputStream fos=new FileOutputStream("..\\myio\\redu.jpg");
//3。加密处理
int b;
while((b=fis.read())!=-1){
fos.write(b^2);
}
//4.释放资源
fos.close();
fis.close();
}
}
3.修改文件中的数据
package Test;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
public class Test3 {
public static void main(String[] args) throws IOException {
/*
文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成以下的数据:
1-2-4-7-8-9
*/
//1.读取数据
FileReader fr=new FileReader("..\\myio\\a.txt");
StringBuilder sb=new StringBuilder();
int ch;
while((ch=fr.read())!=-1){
sb.append((char)ch);
}
fr.close();
//2.排序
Integer[] arr = Arrays.stream(sb.toString()
.split("-"))
.map(Integer::parseInt)
.sorted()
.toArray(Integer[]::new);
//3.写出
FileWriter fw=new FileWriter("..\\myio\\a.txt");
String s=Arrays.toString(arr).replace(", ","-");
String result=s.substring(1,s.length()-1);
fw.write(result);
fw.close();
}
}
缓冲流
BUfferedInputStream字节缓冲流
一次读取一个字节
package mybufferedstream1;
import java.io.*;
public class BufferedStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
需求:
利用字节缓冲流拷贝文件
字节缓冲输入流的构造方法:
public BufferedInputStream(Inputstream is)
字节缓冲输出流的构造方法:
public Bufferedoutputstream(outputstream os)
*/
//1.创建缓冲流的对象
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("..\\myio\\a.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("..\\myio\\copy.txt"));
//2.循环读取并写到目的地
int b;
while((b=bis.read())!=-1){
bos.write(b);
}
//3.释放资源
bos.close();
bis.close();
}
}
一次读取多个字节
package mybufferedstream1;
import java.io.*;
public class BufferedStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
需求:
利用字节缓冲流拷贝文件
字节缓冲输入流的构造方法:
public BufferedInputStream(Inputstream is)
字节缓冲输出流的构造方法:
public Bufferedoutputstream(outputstream os)
*/
//1.创建缓冲流的对象
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("..\\myio\\a.txt"));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("..\\myio\\copy2.txt"));
//2.循环读取并写到目的地
byte[] bytes=new byte[1024];
int len;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
//3.释放资源
bos.close();
bis.close();
}
}
BufferedReader字符缓冲流
输入
package mybufferedstream1;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedStreamDemo3 {
public static void main(String[] args) throws IOException {
/*
字符缓冲输入流:
构造方法:
public BufferedReader(Reader r)
特有方法:
public string readLine()
谈一整行
*/
//1.创建字符缓冲输入流的对象
BufferedReader br=new BufferedReader(new FileReader("..\\myio\\a.txt"));
//细节:
//readLine方法在读取的时候,一次读一整行,遇到回车换行结束
//但是他不会把回车换行读到内存当中
//2.读取数据
String line1=br.readLine();
System.out.println(line1);
String line2=br.readLine();
System.out.println(line2);
//3.释放资源
br.close();
}
}
输出
package mybufferedstream1;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedStreamDemo4 {
public static void main(String[] args) throws IOException {
/*
字符缓冲输出流
构造方法:
public BufferedWriter(Writer r)
特有方法:
public void newLine()
跨平台的换行
*/
//1.创建字符缓冲输出流的对象
BufferedWriter bw=new BufferedWriter(new FileWriter("b.txt",true));
//2.写出数据
bw.write("123");
bw.newLine();
bw.write("456");
bw.newLine();
//3.释放资源
bw.close();
}
}
练习
1.修改文本顺序
package Test;
import java.io.*;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Test4 {
public static void main(String[] args) throws IOException {
//1.读取数据
BufferedReader br=new BufferedReader(new FileReader("..\\myio\\a.txt"));
String line;
TreeMap<Integer,String> tm=new TreeMap<>();
while((line=br.readLine())!=null){
String[] arr=line.split("\\.");
tm.put(Integer.parseInt(arr[0]),arr[1]);
}
br.close();
//2.写出数据
BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myio\\result.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.软件运行次数
package Test;
import java.io.*;
public class Test5 {
public static void main(String[] args) throws IOException {
/*
实现
验证在序运行实数的小程序,
要求如下
1.当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2.程序运行演示如下:
第一次运行控制台输出:欢迎使用本软件,第1次使用免费~
第二次运行控制台输出:欢迎使用本软件,第2次使用免费~
第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~
次数 计数器
int count =0;
*/
//1.把文件中的数字读取到内存中
//原则:
//IO:
//随用随创建
//什么时候不用什么时候关闭
BufferedReader br=new BufferedReader(new FileReader("..\\myio\\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次,欢迎您注册会员后继续使用~");
}
BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myio\\count.txt"));
bw.write(count+"");
bw.close();
}
}
InputStreamReader/OutputStreamWriter转换流
1.转换流的基本用法
JDK11以前可以使用转换流按照指定字符编码读取和写入
JDK11以后字符流中添加了一个新歌构造指定字符编码
练习:读取文件中的数据
package myconvertstream;
import java.io.*;
public class ConvertStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码
//1.字节流在读取中文的时候,是会出现乱码的,但是字符流可以搞定
//2.字节流里面是没有读一整行的方法的,只有字符缓冲流才能搞定
*/
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("..\\myio\\a.txt")));
String line;
while((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
总结
序列化流和反序列化流
ObjectOutputStream序列化流
package myobjectstream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
需求:
利用序列化流/对象操作输出流,把一个对象写到本地文件中
构造方法:
public objectoutputstream(outputstream out)
成员方法:
public final void writeobject(object obj)
把基本流变成高级流
把对象序列化(写出)到文件中去
*/
//1.创建对象
Student stu=new Student("zhangsan",23);
//2.创建序列化流的对象/对线操作输出流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("..\\myio\\b.txt"));
//3.写出数据
oos.writeObject(stu);
//4.释放数据
oos.close();
}
}
package myobjectstream;
import java.io.Serializable;
/*
Serializable接口里面是没有抽象方法,标记型接口
一旦实现了这个接口,那么就表示当前的student类可以被序列化
理解:
-个物品的合格证
*/
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(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 "Student{name = " + name + ", age = " + age + "}";
}
}
ObjectInputStream反序列化流
package myobjectstream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectStreamDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
/*
求:
利用反序列化流/对象操作输入流,把文件中中的对象读到程序当中
构造方法:
public objectInputstream(Inputstream out)
成员方法:
把基本流变成高级流
public obiect readobiect()
把序列化到本地文件中的对象,读取到程序中来
*/
//1.创建反序列化流的对象
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("..\\myio\\b.txt"));
//2.读取数据
Student stu=(Student) ois.readObject();
//3.打印对象
System.out.println(stu);
//4.释放资源
ois.close();
}
}
细节
package myobjectstream;
import java.io.Serial;
import java.io.Serializable;
/*
Serializable接口里面是没有抽象方法,标记型接口
一旦实现了这个接口,那么就表示当前的student类可以被序列化
理解:
-个物品的合格证
*/
public class Student implements Serializable {
@Serial
private static final long serialVersionUID = 3340324615881368858L;
private String name;
private int age;
//transient:瞬态关键字
//作用:不会把当前属性序列化到本地文件当中
private transient String address;
public Student() {
}
public Student(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 "Student{name = " + name + ", age = " + age + "}";
}
}
练习
package Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
public class Test6 {
public static void main(String[] args) throws IOException {
/*
需求:
将多个自定义对象序列化到文件中,但是对象的个数不确定,该如何操作呢
*/
//1.序列化多个对象
Student s1=new Student("zhangsan",25,"邵阳");
Student s2=new Student("lisi",26,"衡阳");
Student s3=new Student("wangwu",27,"隆回");
ArrayList<Student> list=new ArrayList<>();
Collections.addAll(list,s1,s2,s3);
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("..\\myio\\b.txt"));
oos.writeObject(list);
oos.close();
}
}
打印流
打印流不能读只能写
PrintStream字节打印流
构造方法
成员方法
练习
package myprintstream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
public class PrintStreamDemo1 {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
/*
字节打印流:
构造方法
public Printstream(outputstream/File/string)关联字节输出流/文件/文件路径
public Printstream(string fileName,Charset charset)指定字符编码
public Printstream(outputstreamout,boolean autoFlush)自动刷新
public Printstream(outputstream out, boolean autoFlush, string encoding)指定字符编码且自动刷新
成员方法:
public void write(int b)常规方法:规则跟之前一样,将指定的字节写出
public void println(Xxx xx)特有方法:打印任意数据,自动刷新,自动换行
public void print(Xxx xx)特有方法:打印任意数据,不换行
public void printf(string format,object... args) 特有方法:带有占位符的打印语句,不换行
*/
//1.创建字节打印流的对象
PrintStream ps=new PrintStream(new FileOutputStream("..\\myio\\a.txt"),true,"UTF-8");
//2.写出数据
ps.println(97);
ps.print(true);
ps.println();
ps.printf("%s爱上了%s","阿珍","阿强");
//3.释放资源
ps.close();
}
}
PrintWriter字符打印流
构造方法
成员方法
打印流的应用场景
package myprintstream;
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对象。
package myzipstream;
import java.io.*;
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:\\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();
}
}
压缩流
package myzipstream;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
压缩流
需求:
把D:\a.txt打包成一个压缩包
*/
//1.创建File对象表示要压缩的文件
File src=new File("D:\\a.txt");
//2.创建File对象表示压缩包的位置
File dest=new File("D:\\");
//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();
}
}
常用工具包
Commons-io
经典白雪,那我之前敲的代码算什么,算孩子有劲吗
Hutool工具包
练习
1.爬虫获取姓名
package myiotest1;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test1 {
public static void main(String[] args) throws IOException {
/*
制造假数据:
获取男生名字:http://www.haoming8.cn/baobao/10881.htm1
获取姓氏:https://hanyu.baidu.com/shici/detail?pid=0b2f26d4ceddb3ee693fdb1137ee1bed&from=kg0
获取女生名字:http://www.haoming8.cn/baobao/7641.html
*/
//1.定义变量记录网址
String familyNameNet="https://hanyu.baidu.com/shici/detail?pid=0b2f26d4c0ddb3ee693fdb1137ee1b0d&from=kg0";
String boyNameNet="http://www.haoming8.cn/baobao/10881.htm1";
String girlNameNet="http://www.haoming8.cn/baobao/7641.html";
//2.爬取数据,把网址上所有数据拼接成一个字符串
String familyNameStr= webCrawler(familyNameNet);
String boyNameStr= webCrawler(familyNameNet);
String girlNameStr= webCrawler(familyNameNet);
//3.通过正则表达式,把其中符合要求的数据获取出来
ArrayList<String> familyNameTempList=getData(familyNameStr,"(\\W{4})(。|,)",1);
ArrayList<String> boyNameTempList=getData(boyNameStr,"([\\u4E00-\\u9FA5]{2})(。|、)",1);
ArrayList<String> girlNameTempList=getData(girlNameStr,"(.. ){4}..",0);
//4.处理数据
//familyNameTempList(姓氏)
//处理方案:把每一个姓氏拆开并添加到一个新的集合当中
ArrayList<String> familyNameList=new ArrayList<>();
for(String str:familyNameTempList){
//str 赵钱孙李 周吴郑王 冯陈褚卫 蒋沈韩杨
for (int i = 0; i < str.length(); i++) {
char c=str.charAt(i);
familyNameList.add(c+"");
}
}
//boyNameTempList(男生的名字)
//处理方案:去除其中的重复元素
ArrayList<String> boyNameList=new ArrayList<>();
for (String str : boyNameList) {
if(!boyNameList.contains(str)){
boyNameList.add(str);
}
}
//girlNameTempList(女生的名字)
//处理方案:把里面的每一个元素用空格进行切割,得到每一个女生的名字
ArrayList<String> girlNameList=new ArrayList<>();
for (String str : girlNameList) {
String[] arr=str.split(" ");
for (int i = 0; i < arr.length; i++) {
girlNameList.add(arr[i]);
}
}
//5.生成数据
//姓名(唯一)-性別-年龄
ArrayList<String> list=getInfos(familyNameList,boyNameList,girlNameList,70,80);
System.out.println(list);
//写出数据
BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myio\\names.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(boyhs.size()==boyCount){
break;
}
//随机
Collections.shuffle(familyNameList);
Collections.shuffle(boyNameList);
boyhs.add(familyNameList.get(0)+boyNameList.get(0));
}
//2.生成女生不重复的名字
HashSet<String> girlhs=new HashSet<>();
while(true){
if(girlhs.size()==girlCount){
break;
}
//随机
Collections.shuffle(familyNameList);
Collections.shuffle(girlNameList);
boyhs.add(familyNameList.get(0)+girlNameList.get(0));
}
//3.生成男生的信息并添加到集合当中
ArrayList<String> list=new ArrayList<>();
Random r=new Random();
//[18~27]
for (String boyName : boyhs) {
int age=r.nextInt(10)+18;
list.add(boyName+"男"+age);
}
//3.生成女生的信息并添加到集合当中
//[18~25]
for (String girlName : girlhs) {
int age=r.nextInt(8)+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();;
return sb.toString();
}
}
2.随机点名器
1.
package myiotest2;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
public class Test1 {
public static void main(String[] args) throws IOException {
/*需求:
需求:
有一个文件里面存储了班级同学的信息,每一个信息占一行。
格式为:张三-男-23
要求通过程序实现随机点名器。
运行效果:
第一次运行程序:随机同学姓名1(只显示名字)
第二次运行程序:随机同学姓名2(只显示名字)
第三次运行程序:随机同学姓名3(只显示名字)
…
*/
//1.读取文件中学生的姓名
ArrayList<String> list=new ArrayList<>();
BufferedReader br=new BufferedReader(new FileReader("..\\myiotest\\allnames.txt"));
String line;
while((line=br.readLine())!=null){
list.add(line);
}
br.close();
//2.随机抽取
Collections.shuffle(list);
String randomName=list.get(0);
String[] arr2=randomName.split("-");
System.out.println(arr2[0]);
}
}
2.
package myiotest2;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class Test2 {
public static void main(String[] args) throws IOException {
/*
需求:
一个文件里面存储了班级同学的信息,每一个学生信息占一行。
格式为:张三-男-23。
要求通过程序实现随机点名器
运行效果:
70%的概率随机到男生
30%的概率随机到女生
总共随机100万次,统计结果。
注意观察:看生成男生和女生的比例是不是接近于7:3
*/
//1.读取文件中的姓名,按性别存放到数组中
ArrayList<String> boylist=new ArrayList<>();
ArrayList<String> girllist=new ArrayList<>();
BufferedReader br=new BufferedReader(new FileReader("..\\myiotest\\allnames.txt"));
String line;
while((line=br.readLine())!=null){
if(line.split("-")[1].equals("男")){
boylist.add(line);
}else{
girllist.add(line);
}
}
br.close();
//按概率抽取
Random r=new Random();
int a=0,b=0;
for(int i=1;i<=100000;i++){
int x= r.nextInt(10)+1;
Collections.shuffle(boylist);
Collections.shuffle(girllist);
if(x<=7){
a++;
}else{
b++;
}
}
System.out.println(a);
System.out.println(b);
}
}
3.
package myiotest2;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Test3 {
public static void main(String[] args) throws IOException {
/*
需求:
一个文件里面存储了班级同学的姓名,每一个姓名占一行。
要求通过程序实现随机点名器,
第三次必定是张三同学
运行效果:
第一次运行程序
随机同学姓名1
第二次运行程序:
随机同学姓名2
第三次运行程序:张三
*/
//读取文件中学生的姓名
ArrayList<String> list=new ArrayList<>();
BufferedReader br1=new BufferedReader(new FileReader("..\\myiotest\\allnames.txt"));
String line;
while((line=br1.readLine())!=null){
list.add(line);
}
br1.close();
//读取程序运行的次数
BufferedReader br2=new BufferedReader(new FileReader("..\\myiotest\\count.txt"));
String strcount=br2.readLine();
int count=Integer.parseInt(strcount);
br2.close();
count++;
if(count!=3){
Collections.shuffle(list);
Arrays.stream(list.get(0).split("-")).limit(1)
.forEach(System.out::println);
}else{
System.out.println("张三");
}
//将程序运行次数存入文件
BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myiotest\\count.txt"));
bw.write(count+"");
bw.close();
}
}
4.
package myiotest2;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
public class Test5{
public static void main(String[] args) throws IOException {
/*需求:
一个文件里面存储了班级同学的姓名,每一个姓名占一行。
要求通过程序实现随机点名器。
运行结果要求:
被点到的学生不会再被点到。
但是如果班级中所有的学生都点完了, 需要重新开启第二轮点名。
核心思想:
点一个删一个,把删除的备份,全部点完时还原数据。
*/
//1.定义变量,表示初始文件路径,文件中存储所有的学生信息
String src = "..\\myiotest\\names.txt";
//2.定义变量,表示备份文件,一开始文件为空
String backups = "..\\myiotest\\backups.txt";
//3.读取初始文件中的数据,并把学生信息添加到集合当中
ArrayList<String> list = readFile(src);
//4.判断集合中是否有数据
if (list.size() == 0) {
//5.如果没有数据,表示所有学生已经点完,从backups.txt中还原数据即可
//还原数据需要以下步骤:
//5.1 读取备份文件中所有的数据
list = readFile(backups);
//5.2 把所有的数据写到初始文件中
writeFile(src, list, false);
//5.3 删除备份文件
new File(backups).delete();
}
//5.集合中有数据,表示还没有点完,点一个删一个,把删除的备份到backups.txt当中
//打乱集合
Collections.shuffle(list);
//获取0索引的学生信息并删除
String stuInfo = list.remove(0);
//打印随机到的学生信息
System.out.println("当前被点到的学生为:" + stuInfo);
//把删除之后的所有学生信息,写到初始文件中
writeFile(src, list, false);
//把删除的学生信息备份(追加写入)
writeFile(backups, stuInfo, true);
}
private static void writeFile(String pathFile, ArrayList<String> list, boolean isAppend) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter(pathFile, isAppend));
for (String str : list) {
bw.write(str);
bw.newLine();
}
bw.close();
}
private static void writeFile(String pathFile, String str, boolean isAppend) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter(pathFile, isAppend));
bw.write(str);
bw.newLine();
bw.close();
}
private static ArrayList<String> readFile(String pathFile) throws IOException {
ArrayList<String> list = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader(pathFile));
String line;
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
return list;
}
}
5.
package myiotest3;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) throws IOException {
//1.把文件中的所以学生信息读取到内存中
ArrayList<Student> list=new ArrayList<>();
BufferedReader br=new BufferedReader(new FileReader("..\\myiotest\\names.txt"));
String line;
while((line=br.readLine())!=null){
String[] arr=line.split("-");
list.add(new Student(arr[0],arr[1],Integer.parseInt(arr[2]),Double.parseDouble(arr[3])));
}
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;
}
//4.计算每一个人的权重占比范围
for (int i = 1; i < arr.length; i++) {
arr[i]+=arr[i-1];
}
//5.随机抽取
//获取一个0.0~1.0之间的随机数
double number=Math.random();
//判断number在arr中的位置
//二分查找法
//方法回返回:-插入点 -1
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("..\\myiotest\\names.txt"));
for (Student s : list) {
bw.write(s.toString());
bw.newLine();
}
bw.close();
}
}
登录注册
package myiotesy4;
import java.io.*;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) throws IOException {
/*
需求:写一个登陆小案例
添加锁定账号功能)
步骤:
将正确的用户名和密码手动保存在本地的
自userinfo.txt文件中
保存格式为:username=zhangsan&password=123&count=0
让用户键盘录入用户名和密码
比较用户录入的和正确的用户名密码是否一致
如果一致则打印登陆成功
如果不一致则打印登陆失败
输错三次被锁定
*/
//1.读取正确用户名密码和登陆失败次数
BufferedReader br=new BufferedReader(new FileReader("..\\myiotest\\src\\myiotesy4\\userinfo.txt"));
String line=br.readLine();
br.close();
String[] useInfo=line.split("&");
String[] arr1=useInfo[0].split("=");
String[] arr2=useInfo[1].split("=");
String[] arr3=useInfo[2].split("=");
String rightUsername=arr1[1];
String rightPassword=arr2[1];
//count:表示用户连续输错的次数
int count=Integer.parseInt(arr3[1]);
//2.用户键盘录入用户名和密码
if(count==3){
System.out.println("用户账户锁定");
}else {
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("登录成功");
count=0;
}else {
count++;
System.out.println("登录失败,还剩下"+(3-count)+"次机会");
}
//4.把登录失败次数打印到文件当中
BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myiotest\\src\\myiotesy4\\userinfo.txt"));
bw.write("username=" + rightUsername + "&password=" + rightPassword + "&count="+String.valueOf(count));
bw.close();
}
}
}
properties
properties是配置文件的一种
Properties作为双列集合的方法
package myiotest5;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
public class Test1 {
public static void main(String[] args) {
/*
Properties作为Map集合的操作
*/
//1.添加集合的对象
Properties prop=new Properties();
//2.添加数据
//细节:虽然我们可以往Properties当中添加任意的数据类型,但是一般只会往里面添加字符串类型的数据
prop.put("aaa","111");
prop.put("bbb","222");
prop.put("ccc","333");
prop.put("ddd","444");
//3.遍历集合
/*Set<Object> keys=prop.keySet();
for (Object key : keys) {
Object value=prop.get(key);
System.out.println(key+"="+value);
}*/
Set<Map.Entry<Object,Object>> entries=prop.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
Object key=entry.getKey();
Object value=entry.getValue();
System.out.println(key+"="+value);
}
}
}
Properties中特有的读写方法
写
package myiotest5;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Test2 {
public static void main(String[] args) throws IOException {
/*
Properties跟IO流结合的操作
*/
//1.创建集合
Properties prop=new Properties();
//2.添加数据
prop.put("aaa","111");
prop.put("bbb","222");
prop.put("ccc","333");
prop.put("ddd","444");
//3.把集合中的数据以键值对的形式写到本地文件当中
FileOutputStream fos=new FileOutputStream("..\\myiotest\\a.properties");
prop.store(fos,"test");
fos.close();
/*BufferedWriter bw=new BufferedWriter(new FileWriter("..\\myiotest\\a.properties"));
Set<Map.Entry<Object,Object>> entries=prop.entrySet();
for (Map.Entry<Object, Object> entry : entries) {
Object key=entry.getKey();
Object value=entry.getValue();
bw.write(key+"="+value);
bw.newLine();
}
bw.close();*/
}
}
读
package myiotest5;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Test3 {
public static void main(String[] args) throws IOException {
//1.创建集合
Properties prop=new Properties();
//2.读取本地Properties文件里面的数据
FileInputStream fis=new FileInputStream("..\\myiotest\\a.properties");
prop.load(fis);
fis.close();
//3.打印集合
System.out.println(prop);
}
}
拼图游戏
游戏界面
package ui;
import domain.GameInfo;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.util.Properties;
import java.util.Random;
public class GameJFrame extends JFrame implements KeyListener, ActionListener {
//表示游戏的主界面
//彩蛋
int flag;
//创建一个二维数组
//目的:用来管理数据
//加载图片的时候,根据二维数组中的数据,加载对应的图片
int[][] data = new int[4][4];
//记录空白方块在二维数组中的索引
int x = 0;
int y = 0;
//定义一个变量,记录当前展示图片的路径
String path = "..\\puzzlegame\\image\\animal\\animal3\\";
//定义一个二维数组,用来判断胜利
int[][] win = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
//定义一个变量,用来统计步数
int step = 0;
//创建选项下面的条目对象
JMenuItem girlJMenuItem = new JMenuItem("美女");
JMenuItem animalJMenuItem = new JMenuItem("动物");
JMenuItem sportJMenuItem = new JMenuItem("运动");
JMenuItem replayJMenuItem = new JMenuItem("重新游戏");
JMenuItem reLoginJMenuItem = new JMenuItem("重新登录");
JMenuItem closeJMenuItem = new JMenuItem("关闭游戏");
JMenu saveJMenu = new JMenu("存档");
JMenu loadJMenu = new JMenu("读档");
JMenuItem saveItem0 = new JMenuItem("存档0(空)");
JMenuItem saveItem1 = new JMenuItem("存档1(空)");
JMenuItem saveItem2 = new JMenuItem("存档2(空)");
JMenuItem saveItem3 = new JMenuItem("存档3(空)");
JMenuItem saveItem4 = new JMenuItem("存档4(空)");
JMenuItem loadItem0 = new JMenuItem("读档0(空)");
JMenuItem loadItem1 = new JMenuItem("读档1(空)");
JMenuItem loadItem2 = new JMenuItem("读档2(空)");
JMenuItem loadItem3 = new JMenuItem("读档3(空)");
JMenuItem loadItem4 = new JMenuItem("读档4(空)");
JMenuItem accountJMenuItem = new JMenuItem("公众号");
public GameJFrame(int flag){
//彩蛋
this.flag=flag;
System.out.println(this.flag);
//初始化界面
initJFrame();
//初始化菜单
initJMenuBar();
//初始化数据(打乱图片的顺序)
initData();
//初始化图片(根据打乱后的顺序加载图片)
initImage();
//让界面显示出来
this.setVisible(true);
}
//初始化数据(打乱图片的顺序)
private void initData() {
//1.定义一个一维数组
int[] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//2.打乱数组中数据的顺序
//遍历数组,得到数组中的每一个元素,拿着每一个元素跟随机索引上的元素进行交换
Random r = new Random();
for (int i = 0; i < tempArr.length; i++) {
//获取到随机索引
int index = r.nextInt(tempArr.length);
//拿着当前索引上的元素跟随机索引上的元素进行交换
int temp = tempArr[i];
tempArr[i] = tempArr[index];
tempArr[index] = temp;
}
//3.遍历一维数组,把一维数组中的元素放到二维数组中
for (int i = 0; i < tempArr.length; i++) {
if(tempArr[i] == 0){
//记录0的索引
x = i/4;
y = i%4;
}
//i/4 表示二维数组的行索引
//i%4 表示二维数组的列索引
data[i/4][i%4] = tempArr[i];
}
}
//初始化图片
//添加图片的时候,按照二维数组中的数据,来添加图片
private void initImage() {
//清空原本已经出现的所有图片
this.getContentPane().removeAll();
if(victory()){
//添加胜利的图片
JLabel winJLabel = new JLabel(new ImageIcon("..\\puzzlegame\\image\\win.png"));
winJLabel.setBounds(203,283,197,73);
//把图片添加到界面中
this.getContentPane().add(winJLabel);
}
//添加步数
JLabel stepJLabel = new JLabel("步数:"+step);
stepJLabel.setBounds(50,30,100,20);
//把步数添加到界面中
this.getContentPane().add(stepJLabel);
//先添加的图片在上方,后添加的图片在下方
//外循环---把内循环的代码重复执行4次
for (int i = 0; i < 4; i++) {
//内循环---表示在一行添加四张图片
for (int j = 0; j < 4; j++) {
//获取当前要加载图片的序号
int num = data[i][j];
//创建一个JLabel的对象(管理容器)
JLabel jLabel = new JLabel(new ImageIcon(path + num+ ".jpg"));
//指定图片的位置
jLabel.setBounds(105*j+83,105*i+134,105,105);
//给图片添加边框
jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));
//把管理容器添加到界面中
this.getContentPane().add(jLabel);
//添加一次之和number需要自增,表示下一次加载后面一张图片
}
}
//添加背景图片
JLabel background = new JLabel(new ImageIcon("..\\puzzlegame\\image\\background.png"));
background.setBounds(40,40,520,600);
//把背景图片添加到界面中
this.getContentPane().add(background);
//刷新界面
this.getContentPane().repaint();
}
//创建菜单
private void initJMenuBar() {
//创建整个的菜单对象
JMenuBar jMenuBar = new JMenuBar();
//创建菜单上面的两个选项的对象(功能 关于我们)
JMenu functionJMenu = new JMenu("功能");
JMenu aboutJMenu = new JMenu("关于我们");
JMenu changeJMenu = new JMenu("更换图片");
//将每一个选项下面的条目添加到选项当中
//把5个存档,添加到saveJMenu中
saveJMenu.add(saveItem0);
saveJMenu.add(saveItem1);
saveJMenu.add(saveItem2);
saveJMenu.add(saveItem3);
saveJMenu.add(saveItem4);
//把5个读档,添加到loadJMenu中
loadJMenu.add(loadItem0);
loadJMenu.add(loadItem1);
loadJMenu.add(loadItem2);
loadJMenu.add(loadItem3);
loadJMenu.add(loadItem4);
//把美女,动物,运动添加到更换图片当中
changeJMenu.add(girlJMenuItem);
changeJMenu.add(animalJMenuItem);
changeJMenu.add(sportJMenuItem);
//将更换图片,重新游戏,重新登录,关闭游戏,存档,读档添加到“功能”选项当中
functionJMenu.add(changeJMenu);
functionJMenu.add(replayJMenuItem);
functionJMenu.add(reLoginJMenuItem);
functionJMenu.add(closeJMenuItem);
functionJMenu.add(saveJMenu);
functionJMenu.add(loadJMenu);
//将公众号添加到关于我们当中
aboutJMenu.add(accountJMenuItem);
//给选项下面的条目添加监听
girlJMenuItem.addActionListener(this);
animalJMenuItem.addActionListener(this);
sportJMenuItem.addActionListener(this);
replayJMenuItem.addActionListener(this);
reLoginJMenuItem.addActionListener(this);
closeJMenuItem.addActionListener(this);
accountJMenuItem.addActionListener(this);
saveItem0.addActionListener(this);
saveItem1.addActionListener(this);
saveItem2.addActionListener(this);
saveItem3.addActionListener(this);
saveItem4.addActionListener(this);
loadItem0.addActionListener(this);
loadItem1.addActionListener(this);
loadItem2.addActionListener(this);
loadItem3.addActionListener(this);
loadItem4.addActionListener(this);
//将菜单里的两个选项添加到菜单当中
jMenuBar.add(functionJMenu);
jMenuBar.add(aboutJMenu);
//读取存档信息,修改菜单上表示的内容
getGameInfo();
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
public void getGameInfo(){
//1.创建File对象表示所有存档所在的文件夹
File file=new File("..\\puzzlegame\\save");
//2.进入文件夹所获取到里面所有的存档文件
File[] files=file.listFiles();
//3.获取里面的部署,修改菜单
for (File f : files) {
//f :依次表示每一个存档文件
//获取每一个存档文件中的步数
GameInfo gi = null;
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(f));
gi = (GameInfo) ois.readObject();
ois.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取到了步数
int step=gi.getStep();
//把存档的步数同步到菜单当中
//save0 --->0
//save1 ---> 1
//...
//获取存档的文件名 save0.data
String name= f.getName();
//获取当前存档的序号(索引)
int index=name.charAt(4)-'0';
//修改菜单上所表示的文字信息
saveJMenu.getItem(index).setText("存档"+index+"("+step+")步");
loadJMenu.getItem(index).setText("存档"+index+"("+step+")步");
}
}
//初始化界面
private void initJFrame() {
//设置界面的宽高
this.setSize(603,680);
//设置界面的标题
this.setTitle("拼图单机版 v1.0");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中显示
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消默认的居中放置,而是采用绝对定位的方式
this.setLayout(null);
//给整个界面添加键盘的监听
this.addKeyListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
}
//按下不松时,会一直触发该方法
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == 65){
//把界面中的图片全部删除
this.getContentPane().removeAll();
//加载第一张完整的图片
JLabel jLabel = new JLabel(new ImageIcon(path+"all.jpg"));
jLabel.setBounds(83,134,420,420);
//把图片添加到界面中
this.getContentPane().add(jLabel);
//加载背景图片
JLabel background = new JLabel(new ImageIcon("..\\puzzlegame\\image\\background.png"));
background.setBounds(40,40,520,600);
//把背景图片添加到界面中
this.getContentPane().add(background);
//刷新界面
this.getContentPane().repaint();
}
}
//松开按键时,触发该方法
@Override
public void keyReleased(KeyEvent e) {
//判断游戏是否胜利,如果胜利了,就不再接收键盘的输入了
if(victory()){
return;
}
//对上,下,左,右四个方向键进行判断
//左:37 上:38 右:39 下:40
int code = e.getKeyCode();
if(code == 37){
//左
if(y == 3){
//如果空白方块已经在最左边了,就不能再往左移动了
return;
}
System.out.println("向左移动");
data[x][y] = data[x][y+1];
data[x][y+1] = 0;
y++;
step++;
//重新加载图片
initImage();
}else if(code == 38){
//上
if(x == 3){
//如果空白方块已经在最上面了,就不能再往上移动了
return;
}
System.out.println("向上移动");
data[x][y] = data[x+1][y];
data[x+1][y] = 0;
x++;
step++;
//重新加载图片
initImage();
}else if(code == 39){
//右
if(y == 0){
//如果空白方块已经在最右边了,就不能再往右移动了
return;
}
System.out.println("向右移动");
data[x][y] = data[x][y-1];
data[x][y-1] = 0;
y--;
step++;
//重新加载图片
initImage();
}else if(code == 40){
//下
if(x == 0){
//如果空白方块已经在最下面了,就不能再往下移动了
return;
}
System.out.println("向下移动");
data[x][y] = data[x-1][y];
data[x-1][y] = 0;
x--;
step++;
//重新加载图片
initImage();
}else if(code == 65){
initImage();
}else if(code == 87){
data=new int [][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
initImage();
}
}
//判断是否胜利
public boolean victory(){
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i].length; j++) {
if(data[i][j] != win[i][j]){
return false;
}
}
}
return true;
}
@Override
public void actionPerformed(ActionEvent e) {
//获取到当前点击的条目对象
Object obj = e.getSource();
if(obj == replayJMenuItem){
System.out.println("重新游戏");
//计步器清零
step = 0;
//重新打乱图片的顺序
initData();
//重新加载图片
initImage();
}else if(obj == reLoginJMenuItem){
System.out.println("重新登录");
//关闭当前的游戏界面
this.setVisible(false);
//打开登录界面
new LoginJFrame();
}else if(obj == closeJMenuItem){
System.out.println("关闭游戏");
System.exit(0);
}else if(obj == accountJMenuItem){
System.out.println("公众号");
//1.创建集合
Properties prop=new Properties();
//2.读取数据
try {
FileInputStream fis=new FileInputStream("..\\puzzlegame\\game.properties");
prop.load(fis);
fis.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
//3.获取图片的路径
String path=(String)prop.get("account");
//调用下面的showIDialog方法,展示弹框
//showJDialog方法的参数,就是图片的路径
//比如:showJDialog("puzzlegame\\image\\about1.png");
showJDialog(path);
}else if(obj == girlJMenuItem){
System.out.println("美女");
Random r=new Random();
int i;
if(flag==0){
i=r.nextInt(13)+1;
}else{
i=r.nextInt(3)+14;
}
path="..\\puzzlegame\\image\\girl\\girl"+i+"\\";
step=0;
initData();
initImage();
}else if(obj == animalJMenuItem){
System.out.println("动物");
Random r=new Random();
int i=r.nextInt(8)+1;
path="..\\puzzlegame\\image\\animal\\animal"+i+"\\";
step=0;
initData();
initImage();
}else if(obj == sportJMenuItem){
System.out.println("运动");
Random r=new Random();
int i=r.nextInt(10)+1;
path="..\\puzzlegame\\image\\sport\\sport"+i+"\\";
//计步器清零
step=0;
//再次打乱二维数组中的数据
initData();
//重新加载图片
initImage();
}else if (obj==saveItem0||obj==saveItem1||obj==saveItem2||obj==saveItem3||obj==saveItem4){
//获取当前是哪个存档被点击了,获取其中的序号
JMenuItem item=(JMenuItem) obj;
String str=item.getText();
int index=str.charAt(2)-'0';
//之间把游戏的数据写到本地文件中
try {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("..\\puzzlegame\\save\\save"+index+".data"));
GameInfo gi=new GameInfo(data,x,y,path,step);
oos.writeObject(gi);
oos.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
//修改一下存档item上的展示信息
//存档0(xx步)
item.setText("存档"+index+"("+step+"步)");
//修改一下读档item上的展示信息
loadJMenu.getItem(index).setText("存档"+index+"("+step+"步)");
}else if (obj==loadItem0||obj==loadItem1||obj==loadItem2||obj==loadItem3||obj==loadItem4){
System.out.println("读档");
//获取当前是哪个读档被点击了,获取其中的序号
JMenuItem item=(JMenuItem) obj;
String str=item.getText();
int index=str.charAt(2)-'0';
//可以到本地文件中读取数据
GameInfo gi=null;
try {
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("..\\puzzlegame\\save\\save"+index+".data"));
gi=(GameInfo)ois.readObject();
ois.close();
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (ClassNotFoundException classNotFoundException) {
classNotFoundException.printStackTrace();
}
data=gi.getData();
path=gi.getPath();
step=gi.getStep();
x=gi.getX();
y=gi.getY();
//重新刷新界面并加载游戏
initImage();;
}
}
//创建一个弹框对象
JDialog jDialog = new JDialog();
//展示弹框
public void showJDialog(String filepath) {
if (!jDialog.isVisible()) {
JLabel jLabel = null;
//判断传递的字符串是否是一个路径,且必须以jpg或者png结尾
//如果满足,则当做图片处理
//如果不满足,则当做普通字符串处理
if (new File(filepath).exists() && (filepath.endsWith(".png") || filepath.endsWith(".jpg"))) {
jLabel = new JLabel(new ImageIcon(filepath));
} else {
jLabel = new JLabel(filepath);
}
//设置位置和宽高
jLabel.setBounds(0, 0, 258, 258);
//把图片添加到弹框当中
jDialog.getContentPane().add(jLabel);
//给弹框设置大小
jDialog.setSize(344, 344);
//让弹框置顶
jDialog.setAlwaysOnTop(true);
//让弹框居中
jDialog.setLocationRelativeTo(null);
//弹框不关闭则无法操作下面的界面
jDialog.setModal(true);
//让弹框显示出来
jDialog.setVisible(true);
}
}
}
登录界面
package ui;
import cn.hutool.core.io.FileUtil;
import domain.User;
import util.CodeUtil;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LoginJFrame extends JFrame implements MouseListener
{
//表示登录界面
//创建一个集合存储正确的用户名和密码
ArrayList<User> allUsers=new ArrayList<>();
//登录和注册
JButton login = new JButton();
JButton register = new JButton();
//创建文本框对象
JTextField username = new JTextField();
JPasswordField password = new JPasswordField();
JTextField code = new JTextField();
//正确的验证码
JLabel rightCode=new JLabel();
public LoginJFrame(){
//读取本地文件中的用户信息
readUserInfo();
//初始化界面
initJFramed();
//初始化页面
initView();
//让界面显示出来
this.setVisible(true);
}
//读取本地文件中的用户信息
private void readUserInfo() {
//1.读取数据
List<String> userInfoStrList = FileUtil.readUtf8Lines("D:\\idea代码\\untitled1\\puzzlegame\\userinfo.txt");
//2.遍历集合并获取用户信息并创建User对象
for (String str : userInfoStrList) {
String[] userInfoArr=str.split("&");
System.out.println(Arrays.toString(userInfoArr));
String[] arr1 = userInfoArr[0].split("=");
String[] arr2 = userInfoArr[1].split("=");
User u=new User(arr1[1],arr2[1]);
allUsers.add(u);
}
System.out.println(allUsers);
}
//初始化页面
private void initView() {
//1.添加用户名文字
JLabel usernameText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\login\\用户名.png"));
usernameText.setBounds(116,135,47,17);
this.getContentPane().add(usernameText);
//2.添加用户名输入框
username.setBounds(195,134,200,30);
this.getContentPane().add(username);
//3.添加密码文字
JLabel passwordText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\login\\密码.png"));
passwordText.setBounds(130,195,32,16);
this.getContentPane().add(passwordText);
//4.添加密码输入框
password.setBounds(195,194,200,30);
this.getContentPane().add(password);
//5.添加验证码文字
JLabel codeText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\login\\验证码.png"));
codeText.setBounds(133,256,50,30);
this.getContentPane().add(codeText);
//6.添加验证码输入框
code.setBounds(195,256,100,30);
this.getContentPane().add(code);
//随机生成一个验证码
String codeStr= CodeUtil.getCode();
System.out.println(codeStr);
//设置内容
rightCode.setText(codeStr);
//位置和宽高
rightCode.setBounds(300,256,50,30);
//添加鼠标监听事件
rightCode.addMouseListener(this);
//添加到桌面
this.getContentPane().add(rightCode);
//7.添加登录按钮
login.setBounds(123,310,128,47);
login.setIcon(new ImageIcon("..\\puzzlegame\\image\\login\\登录按钮.png"));
//去除按钮的边框
login.setBorderPainted(false);
//去除按钮的背景
login.setContentAreaFilled(false);
//添加鼠标监听事件
login.addMouseListener(this);
this.getContentPane().add(login);
//8.添加注册按钮
register.setBounds(256,310,128,47);
register.setIcon(new ImageIcon("..\\puzzlegame\\image\\login\\注册按钮.png"));
//去除按钮的边框
register.setBorderPainted(false);
//去除按钮的背景
register.setContentAreaFilled(false);
//添加鼠标监听事件
register.addMouseListener(this);
this.getContentPane().add(register);
//7.添加背景图片
JLabel background = new JLabel(new ImageIcon("..\\puzzlegame\\image\\login\\background.png"));
background.setBounds(0,0,470,390);
this.getContentPane().add(background);
}
//初始化界面
private void initJFramed() {
//在创建登录界面的时候,同时给这个界面去设置一些信息
this.setSize(488,430);
//设置界面的标题
this.setTitle("拼图 登录");
//设置界面置顶
this.setAlwaysOnTop(true);
//设置界面居中显示
this.setLocationRelativeTo(null);
//设置关闭模式
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//取消默认的居中放置,而是采用绝对定位的方式
this.setLayout(null);
}
//设置弹窗
public void showJDialog(String content){
//创建一个弹框对象
JDialog jDialog=new JDialog();
//给弹框设置大小
jDialog.setSize(200,150);
//设置弹框置顶
jDialog.setAlwaysOnTop(true);
//设置弹框居中显示
jDialog.setLocationRelativeTo(null);
//设置弹框不关闭永远无法操作下面的界面
jDialog.setModal(true);
//创建JLabel对象管理文字并添加到弹框当中
JLabel warning=new JLabel(content);
warning.setBounds(0,0,200,150);
jDialog.getContentPane().add(warning);
//让弹框显示出来
jDialog.setVisible(true);
}
//鼠标按下并释放事件
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() == login) {
System.out.println("点击了登录按钮");
//获取两个文本输入框中的内容
String usernameInput = username.getText();
String passwordInput = password.getText();
//获取用户输入的验证码
String codeInput = code.getText();
//创建一个User对象
User userInfo = new User(usernameInput, passwordInput);
System.out.println("用户输入的用户名为" + usernameInput);
System.out.println("用户输入的密码为" + passwordInput);
if (codeInput.length() == 0) {
showJDialog("验证码不能为空");
} else if (usernameInput.length() == 0 || passwordInput.length() == 0) {
//校验用户名和密码是否为空
System.out.println("用户名或者密码为空");
//调用showJDialog方法并展示弹框
showJDialog("用户名或者密码为空");
} else if (!codeInput.equalsIgnoreCase(rightCode.getText())) {
showJDialog("验证码输入错误");
} else if (contains(userInfo)) {
System.out.println("用户名和密码正确可以开始玩游戏了");
//关闭当前登录界面
this.setVisible(false);
//打开游戏的主界面
//需要把当前登录的用户名传递给游戏界面
if(usernameInput.equals("yangyuchan")){
new GameJFrame(1);
}else {
new GameJFrame(0);
}
} else {
System.out.println("用户名或密码错误");
showJDialog("用户名或密码错误");
}
login.setBounds(123,310,128,47);
login.setIcon(new ImageIcon("..\\puzzlegame\\image\\login\\登录按钮.png"));
} else if (e.getSource() == register) {
System.out.println("点击了注册按钮");
//关闭当前的登录界面
this.setVisible(false);
//打开注册界面
new RegisterJFrame(allUsers);
} else if (e.getSource() == rightCode) {
System.out.println("更换验证码");
//获取一个新的验证码
String code = CodeUtil.getCode();
rightCode.setText(code);
}
}
//鼠标按下事件
@Override
public void mousePressed(MouseEvent e) {
if(e.getSource()==login){
System.out.println("登录按钮被按下了");
login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按下.png"));
} else if (e.getSource()==register) {
System.out.println("注册按钮被按下了");
register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按下.png"));
}
}
//鼠标释放事件
@Override
public void mouseReleased(MouseEvent e) {
if (e.getSource() == login) {
login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按钮.png"));
} else if (e.getSource() == register) {
register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按钮.png"));
}
}
//鼠标进入事件
@Override
public void mouseEntered(MouseEvent e) {
}
//鼠标离开事件
@Override
public void mouseExited(MouseEvent e) {
}
//判断用户在集合中是否存在
public boolean contains(User userInput){
for (int i = 0; i < allUsers.size(); i++) {
User rightUser=allUsers.get(i);
if(userInput.getUsername().equals(rightUser.getUsername())&&userInput.getPassword().equals(rightUser.getPassword())){
//有相同的代表存在,返回true,后面的不需要再比了
return true;
}
}
//混合结束之后还没有找到就表示不存在
return false;
}
}
注册界面
package ui;
import cn.hutool.core.io.FileUtil;
import domain.User;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
public class RegisterJFrame extends JFrame implements MouseListener{
//表示注册的界面
ArrayList<User> allUsers;
//提升三个输入框的变量的作用范围,让这三个变量可以在本类中所有方法里面可以使用。
JTextField username = new JTextField();
JTextField password = new JTextField();
JTextField rePassword = new JTextField();
//提升两个按钮变量的作用范围,让这两个变量可以在本类中所有方法里面可以使用。
JButton submit = new JButton();
JButton reset = new JButton();
public RegisterJFrame(ArrayList<User> allUsers){
this.allUsers=allUsers;
//初始化界面
initFrame();
initView();
//让界面显示出来
this.setVisible(true);
}
private void initView() {
//添加注册用户名的文本
JLabel usernameText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\register\\注册用户名.png"));
usernameText.setBounds(85, 135, 80, 20);
//添加注册用户名的输入框
username.setBounds(195, 134, 200, 30);
//添加注册密码的文本
JLabel passwordText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\register\\注册密码.png"));
passwordText.setBounds(97, 193, 70, 20);
//添加密码输入框
password.setBounds(195, 195, 200, 30);
//添加再次输入密码的文本
JLabel rePasswordText = new JLabel(new ImageIcon("..\\puzzlegame\\image\\register\\再次输入密码.png"));
rePasswordText.setBounds(64, 255, 95, 20);
//添加再次输入密码的输入框
rePassword.setBounds(195, 255, 200, 30);
//注册的按钮
submit.setIcon(new ImageIcon("..\\puzzlegame\\image\\register\\注册按钮.png"));
submit.setBounds(123, 310, 128, 47);
submit.setBorderPainted(false);
submit.setContentAreaFilled(false);
submit.addMouseListener(this);
//重置的按钮
reset.setIcon(new ImageIcon("..\\puzzlegame\\image\\register\\重置按钮.png"));
reset.setBounds(256, 310, 128, 47);
reset.setBorderPainted(false);
reset.setContentAreaFilled(false);
reset.addMouseListener(this);
//背景图片
JLabel background = new JLabel(new ImageIcon("..\\puzzlegame\\image\\register\\background.png"));
background.setBounds(0, 0, 470, 390);
this.getContentPane().add(usernameText);
this.getContentPane().add(passwordText);
this.getContentPane().add(rePasswordText);
this.getContentPane().add(username);
this.getContentPane().add(password);
this.getContentPane().add(rePassword);
this.getContentPane().add(submit);
this.getContentPane().add(reset);
this.getContentPane().add(background);
}
private void initFrame() {
//对自己的界面做一些设置。
//设置宽高
setSize(488, 430);
//设置标题
setTitle("拼图游戏 V1.0注册");
//取消内部默认布局
setLayout(null);
//设置关闭模式
setDefaultCloseOperation(3);
//设置居中
setLocationRelativeTo(null);
//设置置顶
setAlwaysOnTop(true);
}
//只创建一个弹框对象
JDialog jDialog = new JDialog();
//因为展示弹框的代码,会被运行多次
//所以,我们把展示弹框的代码,抽取到一个方法中。以后用到的时候,就不需要写了
//直接调用就可以了。
public void showDialog(String content) {
if (!jDialog.isVisible()) {
//把弹框中原来的文字给清空掉。
jDialog.getContentPane().removeAll();
JLabel jLabel = new JLabel(content);
jLabel.setBounds(0, 0, 200, 150);
jDialog.add(jLabel);
//给弹框设置大小
jDialog.setSize(200, 150);
//要把弹框在设置为顶层 -- 置顶效果
jDialog.setAlwaysOnTop(true);
//要让jDialog居中
jDialog.setLocationRelativeTo(null);
//让弹框
jDialog.setModal(true);
//让jDialog显示出来
jDialog.setVisible(true);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if(e.getSource()==submit){
//点击了注册按钮
//1.用户名,密码不能为空
if(username.getText().length()==0||password.getText().length()==0||rePassword.getText().length()==0){
showDialog("用户名和密码不能为空");
return;
}
//2.判断两次密码输入是否一致
if(!password.getText().equals(rePassword.getText())){
showDialog("两次密码输入不一致");
return;
}
//3.判断用户名和密码1的格式是否正确
if(!username.getText().matches("[a-zA-Z0-9]{4,16}")){
showDialog("用户名必须是4~16位的数字或字母");
return;
}
if(!password.getText().matches("\\S*(?=\\S{6,})(?=\\S*\\d)(?=\\S*[a-z])\\S*")){
showDialog("密码不符合规则,至少包含1个小写字母,1个数字,长度至少6位");
return;
}
//4.判断用户名是否已经重复
if(containsUsername(username.getText())){
showDialog("用户名已经存在,请重新输入");
return;
}
//5.添加用户
allUsers.add(new User(username.getText(),password.getText()));
//6.写入文件
FileUtil.writeLines(allUsers,"D:\\idea代码\\untitled1\\puzzlegame\\userinfo.txt","UTF-8");
//7.提示注册成功
showDialog("注册成功");
//关闭注册界面,打开登录界面
this.setVisible(false);
new LoginJFrame();
}else if(e.getSource()==reset){
//点击了重置按钮
//清空了三个输入框
username.setText("");
password.setText("");
rePassword.setText("");
}
}
/*
作用:
参数:
判断username在集合中是否存在
用户名
返回值:
true:存在
false:不存在
*/
public boolean containsUsername(String username){
for (User u : allUsers) {
if (u.getUsername().equals(username)){
return true;
}
}
return false;
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
验证码生成
package util;
import java.util.Random;
public final class CodeUtil {
private CodeUtil(){
}
public static String getCode(){
//a-97 A-65
char []str=new char[52];
for (int i = 0; i < str.length; i++) {
if(i<=25){
str[i]=(char)(i+65);
}else{
str[i]=(char)(i+71);
}
}
StringBuilder sb=new StringBuilder();
Random random=new Random();
String code="";
for (int i = 0; i < 4; i++) {
int index = random.nextInt(str.length);
code+=str[index];
}
code+=(random.nextInt(10));
char[] chars = code.toCharArray();
int index = random.nextInt(chars.length);
char temp = chars[4];
chars[4] = chars[index];
chars[index] = temp;
String result = new String(chars);
return result;
}
}
用户类
package domain;
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
/**
* 获取
*
* @return username
*/
public String getUsername() {
return username;
}
/**
* 设置
*
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取
*
* @return password
*/
public String getPassword() {
return password;
}
/**
* 设置
*
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
public String toString() {
return "username=" + username + "&password=" + password;
}
}
游戏信息类
package domain;
import java.io.Serial;
import java.io.Serializable;
public class GameInfo implements Serializable {
@Serial
private static final long serialVersionUID = -5313750424022850690L;
private int[][] data;
private int x=0;
private int y=0;
private String path;
private int step;
public GameInfo() {
}
public GameInfo(int[][] data, int x, int y, String path, int step) {
this.data = data;
this.x = x;
this.y = y;
this.path = path;
this.step = step;
}
/**
* 获取
* @return data
*/
public int[][] getData() {
return data;
}
/**
* 设置
* @param data
*/
public void setData(int[][] data) {
this.data = data;
}
/**
* 获取
* @return x
*/
public int getX() {
return x;
}
/**
* 设置
* @param x
*/
public void setX(int x) {
this.x = x;
}
/**
* 获取
* @return y
*/
public int getY() {
return y;
}
/**
* 设置
* @param y
*/
public void setY(int y) {
this.y = y;
}
/**
* 获取
* @return path
*/
public String getPath() {
return path;
}
/**
* 设置
* @param path
*/
public void setPath(String path) {
this.path = path;
}
/**
* 获取
* @return step
*/
public int getStep() {
return step;
}
/**
* 设置
* @param step
*/
public void setStep(int step) {
this.step = step;
}
public String toString() {
return "GameInfo{data = " + data + ", x = " + x + ", y = " + y + ", path = " + path + ", step = " + step + "}";
}
}