java学习笔记309-323 标准输入输出流,打印流,序列化,Properties

前言
b站java课程学习笔记整理。
b站视频: 黑马程序员全套Java教程_Java基础入门视频教程,零基础小白自学Java必备教程
309. 复制单级文件夹
需求:把一个文件夹下的所有文件复制到指定的位置。
package 文件夹的复制;
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException {
// 创建数据源目录对象
File srcFolder = new File("E:\\Javacode\\JavaSE Code\\rookie");
//获取数据源目录的名称
String folderName = srcFolder.getName();
// 创建目的地目录
File destFolder = new File("idea_test",folderName);
// 如果目的地目录不存在,就新建一个目录
if(!destFolder.exists()){
destFolder.mkdir();
}
// 创建一个文件数组,读取数据源目录下所有文件
File[] listFiles = srcFolder.listFiles();
// 写文件
for(File srcFile:listFiles){
String srcFileName = srcFile.getName();
File destFile = new File(destFolder,srcFileName);
copyFile(srcFile,destFile);
}
}
private static void copyFile(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while((len = bis.read())!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
}
310. 复制多级文件夹
用递归。
package 文件夹的复制;
import java.io.*;
public class DuoJiDemo {
public static void main(String[] args) throws IOException {
// 创建数据源目录对象
File srcFile = new File("E:\\Javacode\\JavaSE Code\\theshy");
// 创建目的地对象
File destFile = new File("idea_test");
// 使用copyFolder方法
copyFolder(srcFile,destFile);
}
private static void copyFolder(File srcFile, File destFile) throws IOException {
//如果是文件夹
if(srcFile.isDirectory()){
// 在目的地下查找同名目录,如果没有就创建个新的
String srcFilename = srcFile.getName(); // “一个文件夹”
File newFolder = new File(destFile,srcFilename); // “idea_test\\一个文件夹”
if(!newFolder.exists()){
newFolder.mkdir();
}
File[] fileList = srcFile.listFiles();
for(File file:fileList){
copyFolder(file,newFolder); //递归,新的文件夹地址取代了destFile。
}
}else{
File newFile = new File(destFile,srcFile.getName());
copyFile(srcFile,newFile);
}
}
private static void copyFile(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while((len = bis.read())!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
}
有点难,注意理解。
311. 复制文件夹的异常处理
保准的使用try...catch...finally
处理。 JDK7的改进方案:
try(定义流对象){
可能有问题的代码;
}catch(异常类名 变量名){
异常的处理代码
}
自动释放资源
JDK9的改进方案:
定义输入流对象
定义输出流对象
try(输入流对象;输出流对象e){
可能有问题的代码;
}catch(异常类名 变量名){
异常的处理代码
}
自动释放资源
四种完整的方法:
package 复制文件的异常处理;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class demo {
public static void main(String[] args) {
}
// 方法一: 直接抛出
private static void method1() throws IOException {
FileWriter fw = new FileWriter("java.txt");
FileReader fr = new FileReader("idea_test\\java.txt");
char[] chars = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chars, 0, len);
}
}
// 方法二: 标准化处理
private static void method2() {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("java.txt");
fr = new FileReader("idea_test\\java.txt");
char[] chars = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chars, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fw == null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fr== null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 方法三: JDK7
private static void method3() {
try (FileWriter fw = new FileWriter("java.txt");
FileReader fr = new FileReader("idea_test\\java.txt")){
char[] chars = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chars, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 方案四: JDK9
private static void method4() throws IOException {
FileWriter fw = new FileWriter("java.txt");
FileReader fr = new FileReader("idea_test\\java.txt");
try (fw;fr){
char[] chars = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chars, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
312. 标准输入流
System
类中有两个静态的成员变量:
public static final InputStream in
标准输入流。public static final PrintStream out
标准输出流。
自己实现键盘录入数据:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
原理就是把系统的标准输入流(字节输入流)转换为字符输入流,再包装成缓冲输入流,之后就可以使用readLine
方法了。
这就是Scanner
的底层原理。
313. 标准输出流
System.out
的本质就是一个字节输出流。
sout
就是System.out.Println()
就是字节输出流的一种使用。
314. 字节打印流
打印流分类:
- 字节打印流:
PrintStream
- 字符打印流:
PrintWriter
打印流的特点:
- 只负责输出数据,不负责读取数据
- 有自己的特有方法
字节打印流
PrintStream(String fileName)
: 使用指定的文件名创建新的打印流。
package 字节打印流;
import java.io.IOException;
import java.io.PrintStream;
public class Demo {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream("idea_test\\rookie\\java.txt");
ps.write(97);
ps.print(97);
ps.println(98);
ps.println(false);
ps.close();
}
}
特有方法print
和println
,使用这两种方法,到txt文档没有转码,写多少就是多少。
315. 字符打印流
方法名 | 说明 |
---|---|
PrintWriter(String fileName) |
使用指定的文件名创建一个新的PrintWriter ,而不需要自动执行刷新 |
PrintWriter(Writer out, boolean autoFlush) |
创建一个新的PrintWriter out :字符输出流autoFlush :一个布尔值,如果为真,则println ,printf ,或者format 方法将刷新输出缓冲区 |
示例代码:
package 字符打印流;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class Demo {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter("idea_test\\java.txt");
pw.println("hello");
pw.flush();
pw.println("world");
pw.flush();
pw.close();
PrintWriter pw2 = new PrintWriter(new FileWriter("idea_test\\java.txt"),true);
pw2.println("ni");
pw2.println("hao");
pw2.close();
}
}
316. 复制java文件打印流改进版
package 复制java文件打印流改进版;
import java.io.*;
public class Demo {
public static void main(String[] args) throws IOException {
String source = "E:\\Javacode\\JavaSE Code\\rookie\\rookie.java";
String destination = "E:\\Javacode\\JavaSE Code\\theshy\\theshy.java";
BufferedReader br = new BufferedReader(new FileReader(source));
PrintWriter pw = new PrintWriter(new FileWriter(destination),true);
String line;
while((line=br.readLine())!=null){
pw.println(line);
}
br.close();
pw.close();
}
}
总结:用这个,这个简单。
317. 对象序列化流
就是把一个对象写入一个文件中。
对象序列化流:ObjectOutputStream
- 将Java对象的原始数据类型和图形写入
OutputStream
。可以使用ObjectInputStream
读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象。
构造方法:
ObjectOutputStream(OutputStream out)
: 创建一个写入指定的OutputStream
的ObjectOutputStream
序列化对象的方法:
void writeObject(Object obj)
: 将指定的对象写入ObjectOutputStream
。
注意:
需要写入的类必须实现序列化接口Serializable
。这个接口不需要重写方法。
package 对象序列化流;
import java.io.Serializable;
public class Student implements Serializable {
private int age;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
System.out.println("使用带参方法定义");
this.name = name;
this.age = age;
}
public Student() {
System.out.println("使用无参方法定义");
}
public void getInfo() {
System.out.println("学生名为" + name);
System.out.println("学生年龄为" + age);
}
}
package 对象序列化流;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Demo {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("java.txt"));
Student s = new Student("林青霞",30 );
oos.writeObject(s);
oos.close();
}
}
318. 对象的反序列化流
构造方法:
ObjectInputStream(InputStream in)
: 创建从指定的InputStream
读取的ObjectInputStream
。
反序列化对象的方法:
Object readObject()
: 从ObjectInputStream
读取一个对象。
package 对象反序列化流;
import 对象序列化流.Student;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Demo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("java.txt"));
Object obj = ois.readObject();
Student s = (Student) obj;
s.getInfo();
ois.close();
}
}
注意: 反序列化流里的Student
类要和序列化流的类一致,不然就会报错ClassNotFoundException
。
319. serialVersionUID&transient
在序列化写入对象时,类会获取一个ID,在修改类后,类会获取一个新ID。这会导致类版本不匹配的报错问题。
解决方案:让这个类提前声明一个ID,并用private
进行修饰。
示例代码:
private static final long serialVersionUID = 42L;
如果一个变量不想被序列化,那就用transient
修饰。
示例代码:
pritave transient String name;
320. Properties作为Map集合的使用
Properties
是一个Map
体系的集合类,可以保存在流中,或者被流加载。
Properties
虽然是Map
体系的,但是没有泛型。
package PropertiesDemo;
import java.util.Properties;
import java.util.Set;
public class Demo {
public static void main(String[] args) {
Properties prop = new Properties();
prop.put("1","孙健耕");
prop.put("2","王晓松");
prop.put("3","林青霞");
Set<Object> keyset = prop.keySet();
for (Object key: keyset){
Object value = prop.get(key);
System.out.println(key +","+ value);
}
}
}
321. Properties作为集合的特有方法
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) |
设置集合的键和值,都是String 类型,底层调用Hashtable 方法put |
String getProperty(String key) |
使用此属性列表中指定的键搜索属性 |
Set<String> stringPropertyNames() |
从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
package PropertiesDemo;
import java.util.Properties;
import java.util.Set;
public class Demo2 {
public static void main(String[] args) {
Properties prop = new Properties();
prop.setProperty("123","孙健耕");
prop.setProperty("1234","孙健");
System.out.println(prop.getProperty("123"));
System.out.println(prop.getProperty("12343"));
Set<String> names = prop.stringPropertyNames();
for(String key: names){
System.out.println(key+","+prop.getProperty(key));
}
}
}
和map
那里的键值对原理是一样的。
322. Properties和IO流相结合
方法名 | 说明 |
---|---|
void load(InputStream inStream) |
从输入字节流读取属性列表(键和元素对) |
void load(Reader reader) |
从输入字符流读取属性列表(键和元素对) |
void store(OutputStream out,String comments) |
将此属性列表(键和元素对)写入此Properties 表中,以适合于使用load(InputStream) 方法的格式写入输出字节流 |
void store(Writer writer, String comments) |
将此属性列表(键和元素对)写入此Properties 表中,以适应使用load(Reader) 方法的格式写入输出字符流。 |
package PropertiesDemo;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class Demo3 {
public static void main(String[] args) throws IOException {
myStore();
myload();
}
private static void myload() throws IOException {
Properties prop = new Properties();
FileReader fr = new FileReader("java.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("123","孙健耕");
prop.setProperty("1234","孙健");
FileWriter fw = new FileWriter("java.txt");
prop.store(fw,null);
fw.close();
}
}
把文件中的属性加载到集合。
323. 游戏次数
需求:用程序实现猜数字小游戏只能试玩三次,如果还想玩,提示想玩请充值。
思路:
- 写一个游戏类,里面有一个猜数字的小游戏。
- 写一个测试类。
#Sun Nov 21 22:29:49 CST 2021
count=3
package 游戏次数;
import java.util.Random;
import java.util.Scanner;
public class Game {
private Game(){};
public static void start(){
Random r = new Random();
int number = r.nextInt(100)+1;
while(true){
Scanner sc = new Scanner(System.in);
System.out.println("请输入你要猜的数字");
int guessNumber = sc.nextInt();
if(guessNumber > number){
System.out.println("你猜的数字"+guessNumber+"大了");
}else if(guessNumber<number){
System.out.println("你猜的数字"+guessNumber+"小了");
}else{
System.out.println("恭喜你猜中了");
break;
}
}
}
}
package 游戏次数;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class Demo {
public static void main(String[] args) throws IOException {
Properties prop = new Properties();
FileReader fr = new FileReader("idea_test\\java.txt");
prop.load(fr);
fr.close();
String count = prop.getProperty("count");
int number = Integer.parseInt(count);
if(number>=3){
System.out.println("请充值");
}else{
Game.start();
number++;
prop.setProperty("count",String.valueOf(number));
FileWriter fw = new FileWriter("idea_test\\java.txt");
prop.store(fw,null);
fw.close();
}
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("count","0");
FileWriter fw = new FileWriter("idea_test\\java.txt");
prop.store(fw,null);
fw.close();
}
}