这里将自己学习java及其应用的一些笔记、积累分享一下,如果涉及到了文章、文字侵权,请联系我删除或调整。
一、Stream
1.1 概述
- Stream(流)——字节数据的读写,抽象成数据在管道中流动
- Stream是单方向的:
输入流,只能用来读取数据
输出流,只能用来输出数据
- 数据只能从头到尾顺序流动一次
二、InputStream / OutputStream
2.1 概述
- InputStream / OutputStream 是字节流的抽象父类
2.2 输出方法
- write(int b)
int的四个字节,只输出末尾的一个字节
[1][2][3][4] ——> [4]
- write(byte[], from, length)
输出数组中,from 开始的 length 个字节
2.3 输入方法
- read()
读取一个字节值,再补三个0字节,转成int。
当文件读取结束时,再读取,得到 -1
三、FileInputStream / FileOutputStream
3.1 概述
- 是 InputStream / OutputStream 的字节流子类
- 文件流,直接插在文件上,可直接读写文件数据
3.2 练习:FileOutputStream测试
package IO_Stream文件流;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test1_FOS_write {
public static void main(String[] args) throws IOException{
System.out.println("");
/* 不管指定的文件是否存在,都会新建空文件
* 路径中的文件夹必须已存在,否则抛异常
*/
FileOutputStream out = new FileOutputStream("d:/f2.txt");
out.write(97);// 00 00 00 61 =>真正输出的只有Int的最后一个字节61
out.write(99);// 00 00 00 63 =>真正输出的只有Int的最后一个字节63
out.write(356);// 00 00 01 64 =>真正输出的只有Int的最后一个字节64,
// 数据被截断,导致数据丢失
out.write(0x00d6);// 00 00 00 d6 => d6
out.write(0x00d0);// 00 00 00 d0 => d0
byte[] a= {101,102,103,104,105,
110,112,113,114,115};
out.write(a,0,10);// 输出byte[]数组a中,0下标开始的10个字节值
out.write(a,3,5);// 输出byte[]数组a中,3下标开始的5个字节值
out.close();// 释放系统资源
}
}
3.3 练习:FileIutputStream测试
package IO_Stream文件流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Test2_FIS_read {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("d:/f2.txt");
int b;
// **习惯性的遍历读取文件字节值的方法**
// 嵌套小括号读取
while ((b=in.read())!=-1) {
System.out.println(b);
}
in.close();
}
}
四、InputStream / OutputStream
4.1 概述
4.2 方法
- write(int b)
- write(byte[], from, length)
- read()
读取一个字节,补三个0字节转成int
读取结束再读取,返回-1
- read(byte[] buff)
按数组长度,读取一批字节值,放入数组,
并返回这一批的字节数量
读取结束再读取,返回-1
4.3 练习:读取文件字节数据
package Stream文件流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class Test1_Stream文件流_read方法测试 {
public static void main(String[] args) throws IOException {
// f2文件共20个字节,数组长度用6,故意让最后一批放不满
FileInputStream in = new FileInputStream("d:/f2.txt");
byte[] arr = new byte[6];
int n;// 用来存储每次read的返回值,即本次读取了多少个数据
// 固定格式,小括号嵌套,将读取语句放入嵌套的括号内
while((n = in.read(arr)) != -1) {
System.out.println(n+"个:"+Arrays.toString(arr));
}
}
}
4.4 练习:文件复制
package Stream文件流;
// 文件复制是字节值的复制,所以不仅仅限于文本,而BufferedReader是字符读入,只可参与字符(文本)复制
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
public class Test2_文件复制 {
public static void main(String[] args) {
// 用户输入欲复制的文件的路径
System.out.println("源文件路径:");
String s1 = new Scanner(System.in).nextLine();
File from = new File(s1);
// 判断路径是否为一个文件,因为不复制文件夹
if(!from.isFile()) {
System.out.println("请输入一个正确的文件名!");
return;
}
// 用户输入欲保存的目标文件的路径及文件名
System.out.println("目标文件路径:");
String s2 = new Scanner(System.in).nextLine();
File to = new File(s2);
// 判断是否为一个文件,复制的数据不能保存为一个“文件夹”
if(to.isDirectory()) {
System.out.println("请输入一个具体的文件,不能是文件夹!");
return;
}
try {
copy(from, to);
System.out.println("完成复制!");
} catch (Exception e) {
System.out.println("复制出错!");
e.printStackTrace();
}
}
// 复制
private static void copy(File from, File to) throws IOException {
/*
* FIS--from
* FOS--to
*/
// 创建数据的输入、输出流
FileInputStream in = new FileInputStream(from);
FileOutputStream out = new FileOutputStream(to);
// // 单字节读写,对硬件设备利用率低,读取、输入效率不高
// int b;
// while((b = in.read())!= -1) {// 从源文件依次读取一个字节
// out.write(b);// 将读取到的一个字节写入目标文件
// }
// 批量读写文件数据
// 批量读取时,惯用数组大小时8K=8192
byte[] arr = new byte[8192];
int n;// 保存每次读取数据的个数
while((n = in.read(arr)) != -1) {
/*
* .write(b, off, len);
* 输出b,从下标off开始,输出len个
*/
out.write(arr,0,n);
}
// 释放系统资源
in.close();
out.close();
}
}
五、ObjectInputStream / ObjectOutputStream
5.1 概述
- 对象的序列化、反序列化
- 把对象的信息,按照固定的字节格式,转成一串字节序列,输出
class A{
int id;
string name;
string gender;
int age;
}
序列化后,为一串以下字符串:
变量值 变量 类名
xxxx xxxxx xxxxxx ……(字节序列)
5.2 方法
- writeObject(Object obj)
序列化输出对象
- readObject()
反序列化恢复对象
5.3 接口
- 被序列化的对象,必须实现 Serializable 接口。
- Serializable 接口
空接口;
标识接口,标识一个类,可以被序列化。
5.4 不序列化的成员
-
static ,静态属于类,不随对象一起被序列化输出
-
transient (临时),只在程序运行期间,在内存中临时存在,不随对象一起被序列化持久保存
5.5 序列化版本
- 序列化版本,用于控制旧版本数据,不允许恢复成新版本的类型。可自己定义,也可有编译器自动添加。
static final long serialVersionUID
- 自己不定义,编译器会添加默认版本id
根据类的定义信息,计算产生一个id值
5.6 练习:Student类序列化输出与读取
package 序列化;
import java.io.Serializable;
//Serializable是一个空接口,没有抽象方法的定义;起一个标识的作用。
public class Student implements Serializable{
// ctrl + 1,序列化版本,其值可以自己定义,也可由编译器产生,如不手动添加,则编译器自动生成
// generated的方法,与编译器默认添加的方法相同,通过类的代码信息计算产生,其值只与类的代码信息有关
private static final long serialVersionUID = -1754877342732270289L;
private int id;
private String name;
// 静态和临时,不会被序列化持久存储
transient private int age;// transient-临时
static private String gender;// static-静态
public Student() {
}
public Student(int id, String name, int age, String gender) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
package 序列化;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Test1_Student类序列化输出测试 {
public static void main(String[] args) throws IOException, Exception {
Student s = new Student(1,"Alice",19,"F");
/*
* Student对象--OOS--FOS--f3文件 ,创建输出流,字节值输出到文件
* OOS--FOS流衔接,配合完成
*/
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("d:/课程项目的临时文件/f3"));
// ObjectOutputStream中的writeObject方法实现序列化输出
out.writeObject(s);
out.close();
}
}
package 序列化;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Test2_Student类序列化读取测试 {
public static void main(String[] args) throws IOException, Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("d:/课程项目的临时文件/f3"));
/* Student对象在序列化写入f3时,保存了原有的类名,变量,变量值等信息。
* f3的字节码在,反序列化方法readObject中已经被重新创建为Student对象
* 但是,其方法返回值为Object对象,所以需要向下转型
*/
Student s= (Student) in.readObject();
in.close();
System.out.println(s);
}
}
六、字符编码、字符集
6.1 概述
- ASC-II
0 到 127
英文字符、标点,及指令字符
- iso-8859-1、Latin-1
扩展到 255
- cjk 字符集 - 中日韩字符集统称
双字节编码,到 65535
- 中国国标码GBK
包含 21003 中文字符
- Unicode 编码
统一码、万国码
有 100万+ 编码位
常用字符表 - 双字节
生僻字符表 - 三字节,或以上
- UTF-8
Unicode 的传输格式
Unicode Transfermation Format
英文 - 单字节
某些字符 - 双字节
中文 - 三字节
特殊符号 - 四字节
下面我们来看几个例子:
- Unicode
a 00 61
中 4e 2d
- GBK
a 61
中 d6 d0
- UTF-8
a 61
中 e4 b8 ad
6.2 Java的字符编码转换
- Unicode <---> 其他编码
- Unicode --> 其他编码
String s = "abc中文";
//Unicode 转成系统的默认编码
byte[] a = s.getBytes();
//Unicode 转成指定的编码
byte[] a = s.getBytes("UTF-8");
- Unicode <-- 其他编码
//把系统默认编码的一组字节值,转成Unicode
String s = new String(byte[]);
//把指定编码的一组字节值,转成Unicode
String s = new String(byte[], "UTF-8");
6.3 练习:编码转换
package 编码转换;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) throws IOException {
String s = "abc中文";// 在Java中都是Unicode编码,全是双字节字符
System.out.println("Java字符串:"+s);
// 调用方法,将字符串s转为不同的编码方式的编码
f(s,null);
f(s,"GBK");
f(s,"UTF-8");
f(s,"Unicode");
}
/* 以下称呼指代相同的东西:
* 编码 -- encoding
* 字符集 -- charset
*/
private static void f(String s, String encoding) throws IOException {
// Unicode字符串s,转换成其他编码的一组字节值
byte[] a;
if(encoding == null) {
// 为提供编码方式,转为操作系统的默认编码(本系统为GBK)
a = s.getBytes();
}else {
// 提供了编码方式,转为指代编码方式的编码
a = s.getBytes(encoding);
}
System.out.println(encoding+"\t"+Arrays.toString(a));
/*----------------------------------------------------------*/
String str;
if(encoding == null) {//从默认编码,转为Unicode
str = new String(a);
}else {//从指定编码,转为Unicode
str = new String(a,encoding);
}
System.out.println(encoding+"\t"+str);
}
}