1.常见的编码
GBK、GB2312:国标编码,GBK包含简体中文和繁体中文,而GB2312只包含简体中文。
UNICODE编码:java提供的16进制编码,可以描述世界上任意的文字信息。由于使用16进制编码,编码体积太大,造成网络传输的负担。
ISO8859-1:国际通用编码,不支持中文。(浏览器默认编码)
UTF编码:相当于结合了UNICODE、ISO8859-1,支持所有语言且体积较小,常用的就是UTF-8编码形式。
2.乱码产生原因
95%的乱码产生于编解码不一致
读取java运行属性
import java.io.*;
import java.nio.file.Paths;
/**
* 乱码的产生
* Author: qqy
*/
public class Test {
public static void main(String[] args) {
File file=Paths.get("E:","JAVA","Test.txt").toFile();
try( FileOutputStream out=new FileOutputStream(file);
) {
//统一采用UTF-8
out.write("你好hello".getBytes("ISO-8859-1"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.内存流
除了文件之外,IO的操作也可以发生在内存之中。发生在内存中的操作流称为内存操作流。
-
3.1 分类:
字节内存流:ByteArrayInputStream、ByteArrayOutputStream(输出无参数)
字符内存流:CharArrayReader、CharArrayWriter
-
3.2应用
- 内存流实现字母转换
import java.io.*;
/**
* 内存流应用
* Author: qqy
*/
public class Test {
public static void main(String[] args) {
//方法一:
String msg="hello";
//取得内存流
ByteArrayInputStream inputStream=new ByteArrayInputStream(msg.getBytes());
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
int len=-1;
while((len=inputStream.read())!=-1){
outputStream.write(Character.toUpperCase(len));
}
//直接将内存输出流输出
System.out.println(outputStream);
//方法二:
try(InputStream in = new ByteArrayInputStream(msg.getBytes());
OutputStream out = new ByteArrayOutputStream()//默认构造方法缓存区32个字节(32)
){
byte[] buff=new byte[3];
int count=0;
while((len=in.read(buff))!=-1) {
for (int i = 0; i < len; i++) {
byte b=buff[i];
if(b>='a'&&b<='z') {
count++;
buff[i] = (byte) (buff[i] - 32);
}
}
out.write(buff,0,len);
}
//OutputStream中没有toByteArray,当前情况下要使用必须向下转型
byte[] newData= ((ByteArrayOutputStream) out).toByteArray();
System.out.println(new String(newData));
System.out.println("转换次数:"+count);
}catch (IOException e){
}
}
}
- 文件合并(考虑到内存,文件不宜过大)
import java.io.*;
import java.nio.file.Paths;
/**
* 内存流合并两个文件(代码量重复过多)
* Author: qqy
*/
public class Test1 {
public static void main(String[] args) {
File file1=Paths.get("E:","JAVA","Test.txt").toFile();
File file2=Paths.get("E:","JAVA","Test1.txt").toFile();
//目标文件
File file3=Paths.get("E:","JAVA","destTest.txt").toFile();
try(FileInputStream in1=new FileInputStream(file1);
FileInputStream in2=new FileInputStream(file2);
ByteArrayOutputStream memoryOut=new ByteArrayOutputStream();
FileOutputStream out=new FileOutputStream(file3);
){
//读文件并写入内存流
byte[] buff=new byte[5];
int len=-1;
while((len=in1.read(buff))!=-1){
memoryOut.write(buff,0,len);
}
while((len=in2.read(buff))!=-1){
memoryOut.write(buff,0,len);
}
//写入文件
out.write(memoryOut.toByteArray());
}catch (IOException e){
}
}
}
优化后:
import java.io.*;
import java.nio.file.Paths;
/**
* 内存流合并两个文件(代码量重复过多)
* Author: qqy
*/
public class Test1 {
public static void main(String[] args) {
File file1=Paths.get("E:","JAVA","Test.txt").toFile();
mergeFileBetter(new String[]{
"E:"+File.separator+"JAVA"+File.separator+"Test.txt",
"E:"+File.separator+"JAVA"+File.separator+"Test1.txt"
},"E:"+File.separator+"JAVA"+File.separator+"destTest.txt");
}
public static void mergeFileBetter(String[] mergePaths,String outPaths){
//参数校验
File[] files=new File[mergePaths.length];
//初始化所有输入文件
for(int i=0;i<mergePaths.length;i++){
files[i]=new File(mergePaths[i]);
}
//输出流
try(ByteArrayOutputStream memoryOut=new ByteArrayOutputStream();
FileOutputStream out=new FileOutputStream(outPaths)
) {
//遍历合并的文件,输入到内存流
for (File f : files) {
try (FileInputStream in = new FileInputStream(f)) {
//读文件并写入内存流
byte[] buff=new byte[3];
int len=-1;
while((len=in.read(buff))!=-1){
memoryOut.write(buff,0,len);
}
} catch (IOException e) {
}
}
//内存流输出到文件
out.write(memoryOut.toByteArray());
}catch (IOException e){
}
}
}
4.打印流
输出流的进化版
-
4.1 自定义打印流:
import java.io.*;
import java.nio.file.Paths;
/**
* 设计打印流
* Author: qqy
*/
public class DesignPrintStream {
public static void main(String[] args) {
//DesignPrintStream print = new DesignPrintStream(System.out);
DesignPrintStream print =null;
try {
print = new DesignPrintStream(
new FileOutputStream(Paths.get("E:","JAVA","Test.txt").toFile())
);
print.println("Hello");
print.println(10);
print.println(10.0d);
print.println(true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private OutputStream outputStream;
public DesignPrintStream(OutputStream outputStream){
this.outputStream=outputStream;
}
public void print(String str){
try {
//核心在于OutputStream提供的write
outputStream.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public void println(String str){
print(str+"\r\n");
}
public void println(int value){
println(String.valueOf(value));
}
public void println(double value){
println(String.valueOf(value));
}
public void println(boolean value){
println(String.valueOf(value));
}
}
-
4.2 系统提供的打印流
字节打印流:PrintStream 字符打印流:PrintWriter
- 打印流应用的是装饰设计模式(基于抽象类):核心依然是某个类(OutputSream)的功能(write()),但是为了得到更好的操作效果,让其支持的功能更多。
-
优点:扩展功能方便,需要不同的功能时只需要更换装饰类即可。 缺点:类结构复杂
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.nio.file.Paths;
/**
* Author: qqy
*/
public class Test {
public static void main(String[] args) {
PrintStream print =null;
try {
print = new PrintStream(
new FileOutputStream(Paths.get("E:","JAVA","Test.txt").toFile())
);
print.println("Hello");
print.println(10);
print.println(10.0d);
print.println(true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
-
4.3 格式化输出
public PrintStream printf(String format, Object ... args)
- 简答:
System是类(java.lang.System)
out / err 是对象(PrintStream的属性,java.io.PrintStream)/ in是对象(java.io.InputStream)
println是PrintStream类的成员方法,out对象的方法 / read是InputStream类的成员方法,in对象的方法
/**
* Author: qqy
*/
public class TestFormat {
public static void main(String[] args) {
System.out.printf("%s","bonjour");
System.out.printf("姓名:%s,年龄:%d,身高:%.2f","李四",18,180.6);
System.out.println();
//正:右对齐,负:左对齐
System.out.printf("姓名:%4s\n年龄:%-4d\n身高:%8.2f\n","张三",25,168.8);
//java.util.Formatter
//String.format,System.out.printf用法一直
String str=String.format("姓名:%s\n年龄:%d\n身高:%.2f\n","张三",25,168.8);
//System是类,out是对象,
System.out.println(str);
}
}
5.System对I/O的支持
- 输出:均是打印流PrintStream的对象
标准输出——显示器 System.out
错误输出——System.err
- 输入:输入流InputStream的对象
标准输入——键盘 System.in
标准输出:
public class Test {
public static void main(String[] args) {
try{
//让OutputStream的输出位置变为屏幕
OutputStream out=System.out;
out.write("hello\n".getBytes());
System.err.println("bonjour");
Integer.parseInt("123aaa");
}catch (NumberFormatException e){
System.out.println(e.getMessage());
System.err.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
}
标准输入:
有限制:
import java.io.IOException;
import java.io.InputStream;
/**
* Author: qqy
*/
public class Test1 {
public static void main(String[] args) throws IOException {
//从键盘输入
InputStream in=System.in;
//数组长度固定,可能无法读取全部内容
byte[] data=new byte[6];
System.out.println("请输入内容:");
int len=in.read(data);
System.out.println(new String(data,0,len));
}
}
优化:
import java.io.*;
/**
* Author: qqy
*/
public class Test3 {
public static void main(String[] args) {
InputStream in=System.in;
byte[] buff=new byte[5];
System.out.println("请输入内容:");
int len=-1;
//利用内存流消除限制
try(ByteArrayOutputStream out=new ByteArrayOutputStream()){
while((len=in.read(buff))!=-1){
out.write(buff,0,len);
//当读取的长度数组的长度,则读取完成,跳出循环
if(len<buff.length){
break;
}
}
System.out.println(new String(out.toByteArray()));
}catch (IOException e){
System.out.println(e.getMessage());
}
}
}
6.两种输入流
原生InputStream的进化版
-
6.1 BufferedReader(了解)
——readLine() 读取一行输入
import java.io.*;
/**
* 利用BufferedReader实现键盘输入
* Author: qqy
*/
public class Test4 {
public static void main(String[] args) {
//BufferedReader->InputStreamReader->InputStream
try( InputStream inputStream=System.in;
InputStreamReader inputStreamReader=new InputStreamReader(inputStream);
BufferedReader reader=new BufferedReader(inputStreamReader)
){
String line;
System.out.println("请输入内容:");
while(!(line=reader.readLine()).equals("q")){
System.out.println(line);
}
}catch(IOException e){
System.out.println(e.getMessage());
}
}
}
-
6.2 Scanner(java.util.Scanner)
- 判断是否有指定类型数据输入: public boolean hasNextXXX()
- 取得指定类型的数据: public 数据类型 nextXXX()
- 自定义分隔符:public Scanner useDelimiter(Pattern pattern)
- 构造方法:public Scanner(InputStream source)
- 输出使用打印流,输入使用Scanner类
Scanner读取数据:
import java.util.Scanner;
/**
* Scanner读取数据
* Author: qqy
*/
public class Test2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
//判断是否有内容
if (scanner.hasNext()) {
//输出输入的内容(空格被忽略)
System.out.println(scanner.next());
}
while (true) {
System.out.println("请输入年龄:");
if (scanner.hasNextInt()) {
System.out.println("年龄是:" + scanner.nextInt());
break;
} else {
System.out.println("您输入的格式有误,请重新输入:");
scanner.next();//丢弃不符合要求的数据
}
}
System.out.println("请输入出生日期:");
//正则表达式 d——整数 数字——长度
if (scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
System.out.println(scanner.next());
}
}
}
Scanner读取文件:
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner;
/**
* Scanner读取文件
* Author: qqy
*/
public class Test5 {
public static void main(String[] args) {
try (Scanner scanner=new Scanner(Paths.get("E:","JAVA","Test.txt"))){
while(scanner.hasNext()){
//声明文件的分隔符是\n
scanner.useDelimiter("\n");
System.out.println(scanner.next());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
System 拓展:
1.系统属性
import java.util.Properties;
/**
* 系统属性
* Author: qqy
*/
public class Test6 {
public static void main(String[] args) {
//系统属性
Properties properties=System.getProperties();
//常用系统属性
//user.home / user.dir / java.home / path.separator / file.separator
//获取用户目录
String userHome=(String)properties.get("user.home");
System.out.println(userHome);
}
}
2.系统环境变量
import java.io.File;
import java.nio.file.Paths;
import java.util.Map;
/**
* 系统环境变量
* Author: qqy
*/
public class Test7 {
public static void main(String[] args) {
//返回Map接口的实例化对象
Map<String, String> env = System.getenv();
for (Map.Entry<String, String> entry : env.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
//JAVA_HOME 配置的环境变量
//SystemDrive 获取驱动盘
//Path
//ProgramData 存放数据
//ProgramW6432 获取安装目录
//TEMP 临时目录
//NUMBER_OF_PROCESSORS 处理器的核数
System.out.println(System.getenv("JAVA_HOME"));
//将文件写入临时目录
File tempFile = Paths.get(
System.getenv("TEMP"),
"abc.txt")
.toFile();
System.out.println(tempFile.getAbsolutePath());
}
}
7.序列化
将内存中的对象变为二进制数据流的形式进行传输或保存于文本中。
-
7.1 初识
1.Java提供的一种序列化(JDK提供) 远程方法调用(RPC)
序列化:将内存转换为字节数组,可在网络中传输,保存文件
Object(In Memory) -> byte[]
反序列化:
byte[] -> Object(In Memory)
2. Object -> JSON (前端开发 JavaScript) Person(name,age) -> {"name":"Jack", "age": 22}
JSON -> Object
3. Object -> XML (XML文件——可扩展的标志语言)(JDK提供)
XML -> Object
4.Java序列化:
序列化对象的属性信息
反序列化不会执行构造方法和构造块
-
7.2 实现
Java中的类如果要被序列化输出,该类必须实现Serializable接口,该接口是一个标识接口,表示该类具有序列化的功能。
-
7.3 序列化与反序列化操作:
要想实现序列化与反序列化的对象操作,需要使用java.io包中提供的两个类:ObjectOutputStream、 ObjectInputStream
对象序列化输出—ObjectOutputStream 对象反序列化输入—ObjectInputStream
- 将对象序列化输出方法:
public final void writeObject(Object obj) throws IOException
- 将对象反序列化输入方法:
public final Object readObject() throws IOException, ClassNotFoundException
- 使用Serializable序列化输出时,默认将对象的所有属性以及值均序列化以及反序列化。若希望某些属性值不进行序列化输出,可以在属性前加transient关键字
代码示例:
import java.io.*;
import java.nio.file.Paths;
/**
* Author: qqy
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file=Paths.get("E:","JAVA","Test.txt").toFile();
//取得相应输出流
Person1 per=new Person1("张三",18);
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
//数据序列化输出
oos.writeObject(per);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
//数据反序列化输入
Object res=ois.readObject();
System.out.println(res); //Person{name=张三 age=0"}
ois.close();
}
}
//Serializable 标识接口
class Person1 implements Serializable{
private String name;
private transient int age;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name=" + name +
" age=" + age +
"\"}";
}
}