Java IO流超详细笔记
引言:
本文主要分享了有关IO的知识,从IO的分类开始依次说了字节流(读写相关的操作、字节缓冲流)、字符编码(编码和解码问题)、字符流(读写相关的操作、字符缓冲流)、其他比较重要的流(内存操作流程、打印流、对象流......)、序列化反序列化以及Properties类(store和load方法)
@[toc]
1. IO流概述
用来处理设备之间的数据传递,是内存与存储设备之间传输数据的通道;类似于水借助管道传输而数据则借助流传输;
1.1 流的分类
按方向:
- 输入流:将<存储设备>中的内容读入到<内存>中;
- 输出流:将<内存>中的内容写入到<存储设备>中;
按流的类型:
字节流:以字节为单位,可以读写所有数据;
字符流:以字符为单位,只能读写文本数据;
注:
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容就用字符流,其他用字节流;(如果不知道用字节流)
按功能:
- 节点流:具有实际传输数据的读写功能;
- 过滤流:在节点流的基础上增强功能;
1.2 路径问题
绝对路径:"D:\work\kaka.txt" 必须存在
相对路径:"Files\kaka.txt" 当前项目路径 ,寻找该路径和文件
2. 字节流
在IO包下,字节流的父类(抽象类):不能实例化需要借助其子类;
2.1 字节流写数据
2.1.1 写数据的步骤
OutputStream:字节输出流(抽象类)
FileOutputStream:文件输出流(子类)
void flush():刷新此输出流并强制写出所有缓冲的输出字节;
public int write(int n){}:将指定的字节写入此输出流
步骤:
- 创建输出流对象
- 写数据
- 释放资源
public static void main(String[] args) throws IOException {
//创建输出流对象
FileOutputStream fos = new FileOutputStream("fox.txt");
//写数据
fos.write("helloworld".getBytes());//字符串转化为字符数组
//释放资源
fos.close();
}
注:
- 创建文件输出流对象的过程是非Java语言实现的,是调用创建系统资源创建文件;
- 将文件输出流对象指向fos就是指向那个文件
- 如果流已经关闭了,那么不能再给流指向的文件中输出数据了
2.1.2 写数据的方法
- public void write(int b):写一个字节,将指定的字节写入此输出流
- public void write(byte[] b):一次写多个字节,将b数组中所有字节写入输出流;
- public void write(byte[] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入此输出流;
public static void main(String[] args) throws IOException {
//创建一个字节输入流对象
FileOutputStream fos = new FileOutputStream("fos.txt");
//写一个字节
fos.write(97);//a
//写一个字节数组
//定义一个字节数组
byte[] bytes = {
97,98,99,100,101};
fos.write(bytes);
//写字节数组的一部分到输出流中
fos.write(bytes,2,3);//从索引为2开始读取3个长度
//释放资源
fos.close();
}
2.1.3 写数据的追加及换行
追加:
- public FileOutputStream(String name,boolean append):将指定的字节写入文件的末尾处(第二个参数为true)
换行,加入换行符:
- Windows系统:\r\n
- Linux系统: \n
- Mac系统 :\r
public static void main(String[] args) throws IOException {
//创建一个文件输出流对象
FileOutputStream fos = new FileOutputStream("fos.txt", true);
//写内容
for(int i = 0 ; i < 10 ; i ++) {
fos.write(("hello"+i).getBytes());
//写入换行符号
fos.write("\r\n".getBytes());
}
//关闭资源
fos.close();
}
- 输出10个换过行的hello以及对应的0~9的下标
2.1.4 输出流加入异常处理操作
2.1.4.1 try...catch
public static void main(String[] args) {
//创建文件输出流对象
FileOutputStream fos = null; //初始化
try {
fos = new FileOutputStream("fos.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//写数据
try {
fos.write("hello,java".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//释放资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2.1.4.1 try...catch...catch
public static void main(String[] args) {
//创建文件输出流对象
FileOutputStream fos = null;
try{
fos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
fos.close();
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
}
2.1.4.1 try...catch..finally(标准处理方式)
public static void main(String[] args) {
//创建文件输出流对象
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos.txt");
fos.write("hello".getBytes());
}catch(IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(fos!=null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2 字节流读数据
2.2.1 一次读一个字节
InputStream:字节输入流(抽象类)
子类:FileInputStream:文件输入流(子类)
void close():关闭输入流并释放与该流关联的所有系统资源;
public int read(){}:从输入流中读取数据的下一个字节;
步骤:
- 创建文件字节输入流对象
- 读数据
- 释放资源
public static void main(String[] args) throws IOException {
//创建文件字节输入流对象
FileInputStream fis = new FileInputStream("kaka.txt");
int by = 0;
//读取赋值判断
while((by = fis.read())!= -1){
//-1作为文件是否读取完毕条件
System.out.println((char)by);
}
//释放资源
fis.close();
}
2.2.2 一次读一个字节数组
- public int read(byte[] b){}:从输入流中读取一定数量的字节,将其存放在缓冲区数组b中,也就是一次读取一个字节数组;如果到达尾部,返回-1;
- public int read(byte[] b,int off,int len){}:将输入流中最多的len个数据字节读入byte数组;
public static void main(String[] args) throws IOException {
//创建文件字节输入流对象
FileInputStream fis = new FileInputStream("kaka.txt");
//一次读取一个字节数组
byte[] bytes = new byte[1024] ; //1024或1024倍数
int len = 0; //读取的实际字节数
//读取,赋值,判断
while((len = fis.read(bytes))!=-1){
//每次从0开始读,读取实际长度
System.out.println(new String(bytes,0,len));
}
}
- 返回值就是实际读取的字节数
- 一次读取的字节数组要么是1024要么是1024倍数
2.3 字节流读写文本
在当前项目文件下:
源文件: a.txt 用字节输入流读取a.txt文件内容
目标文件:b.txt 用文件输出流输出b.txt
public static void main(String[] args) throws IOException {
//源文件a.txt
FileInputStream fis = new FileInputStream("a.txt") ;
//目标文件:b.txt
FileOutputStream fos = new FileOutputStream("b.txt") ;
//一次读取一个字节
int by = 0 ;
while((by=fis.read())!=-1) {
//读一个字节,写一个字节
fos.write(by);
}
//释放资源
fos.close();
fis.close();
}
2.4 字节流读写图片
- 源文件:d盘 a.JPG
- 目的地:复制到当前项目的目录 b.JPG
public static void main(String[] args) throws IOException {
//封装源文件
FileInputStream fis = new FileInputStream("d:\\a.JPG");
//封装目的地
FileOutputStream fos = new FileOutputStream("b.JPG");
//一次读取一个字节数组
byte[] bytes = new byte[1024];
int len = 0;
while((len=fis.read(bytes))!=-1) {
//写的操作
fos.write(bytes, 0, len);
}
//释放资源
fos.close();
fis.close();
}
3. 字节缓冲流
3.1 缓冲流
加入了数组的缓冲区效果使得字节流一次读写一个数组的速度比一次读写一个字节的速度要快,Java本身也提供了字节缓冲区流,减少访问磁盘的次数;不过要想实现文件的操作还需要使用字节流来操作;
3.2 字节缓冲输出流
自带一个缓冲区大小
BufferedOutputStream:输出流,将各个字节写入底层代码中,继承OutputStream
- BufferedOutputStream(OutputStream out):默认的缓冲区大小足够大
- public void write(int b):写数据
- public void write(byte[] bytes,int offerset,int len):从指定位置开始写
public static void main(String[] args) throws IOException{
//创建字节缓冲输出流对象
BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
//写数据
bos.write("hello".getBytes());
//释放资源
bos.close();
}
3.3 字节缓冲输入流
BufferedInputStream:输入流,读入程序中,继承InputStream
- BufferedInputStream(InputStream in):创建一个 BufferedInputStream和保存它的参数,输入流 in,供以后使用
- BufferedInputStream(InputStream in, int size):创建一个具有指定的缓冲区大小 BufferedInputStream,并保存它的参数,输入流 in,供以后使用
- 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中;也可直接close释放资源的同时,将缓冲器的数据一次性写入到文件里;
public static void main(String[] args) throws IOException {
//创建字节缓冲输入流对象
BufferedInputStream bis =
new BufferedInputStream(new FileInputStream("bos.txt")) ;
//读取数据,一次读取一个字节
int by = 0 ;
while((by=bis.read())!=-1) {
System.out.print((char)by);
}
//释放资源
bis.close();
}
- 字节缓冲流它只是提供一个缓冲区,提高执行速度,最基本的流的读写操作还需要用最基本流(InputStream/outputStream)
3.4 使用字节缓冲流的方式复制MP4文件
- 源文件:D:\计算机语言的简单描述.mp4
- 目的地:当前项目下copy.mp4
public static void main(String[] args) throws IOException {
//封装源文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\计算机语言的简单描述.mp4"));
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp4"));
//一次读取一个字节
int by = 0;
while((by = bis.read())!= -1){
bos.write(by);
}
//释放资源
bos.close();
bis.close();
}
4. 字符编码
常见的字符编码:
- IOS-8859-1:西欧、东南亚国家,拉丁文码表
- UTF-8:针对Unicode的可变长度字符编码,一个中文对应的三个字节
- GB2312:简体中文(国标)
- GBK:简体中文、扩充(Eclipse默认)
- BIG5:台湾,繁体中文
- getBytes(String charset):指定编码集进行编码
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "abc12我";
byte[] bs = str.getBytes("GBK");//获得字符串的二进制表现形式
for(int i = 0; i<bs.length;i++){
System.out.println("GBK解码:" + bs[i]);//GBK解码:97、98、99、49、50、-50、-48
}
//解码
String str2 = new String(bs,"BIG5");
System.out.println("GBK编码BIG5解码:" + str2);//GBK编码BIG5解码:abc12扂
byte[] bs2 = str2.getBytes("BIG5");//解码的基础上用BIG5编码,编码完后再用GBK解码
String str3 = new String(bs2,"GBK");
System.out.println("BIG5编码BIG5解码,再用GBK解码:" +str3);//BIG5编码BIG5解码,再用GBK解码:abc12我
String str4 = "白赟asdf123";
//编码
byte[] bs3 = str4.getBytes("UTF-8");
//解码
String str5 = new String(bs3,"UTF-8");
System.out.println("UTF-8:" +str5);//UTF-8:白赟asdf123
String s = "卡卡";//在BIG5中的体现
byte[] b = s.getBytes("GBK");
String s1 = new String(b,"BIG5");
System.out.println("卡卡在BIG5解码:"+s1);//BIG5:縐縐
}
- 当编码和解码方式不一致时会出现乱码;
- 中文的存储底层是以字节的形式存储;
5. 字符流
字符流= 字节流+ 编码格式(如果编码格式:统一gbk格式,构造方法中可以不指定格式默认)
5.1 编码的转换
字符流的父类(抽象类):IO包下
Reader:字符输入流
- InputStreamReader(InputStream in):使用默认的字符集格式
- InputStreamReader(InputStream in,Charset cs):使用指定的字符集格式
Writer:字符输出流
- OutputStreamWriter(OutputStream out):使用默认的字符集格式
- OutputStreamWriter(OutputStream out,Charset cs):使用指定的字符集格式
使用步骤:
创建节点流并设置字符编码集
读写数据
关闭流
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException{
//创建一个字符输出对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"UTF-8");
//写操作
osw.write("卡卡");
//释放资源
osw.close();
}
}
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException{
//创建一个字符输入流对
InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8");
//读的操作
int ch = 0;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
//关闭资源
isr.close();
}
}
- 可设置字符的编码方式但是编码和解码要一致;
5.2 写文件
针对字符输出流写数据的功能:
- public void write(int c):写入单个字符
- public void write(char[] cbuf):给当前输出流写入一个字符数组
- public abstract void write(char[] cbuf, int off,int len):写入字符数组的一部分
- public void write(String str):写入字符串内容
- public void write(String str, int off,int len):写入字符串的一部分内容
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
//写入单个字符
osw.write('a');
//给当前输出流写入一个字符数组
char[] chs = {
'a','b','c','d'};
osw.write(chs);
//写字符数组的一部分
osw.write(chs,0,2);
//写入字符串内容
String str = "不断学习的卡卡";
osw.write(str);
//写字符串的一部分
osw.write(str,1,3);
//刷新
osw.flush();
//关闭资源
osw.close();
}
}
5.3 读文件
针对字符输入流读数据的功能:
public int read(){}:一次读取一个字符
public int read(char[] c){}:一次读入一个字符数组
public int read(char[] b,int off,int len){}:将字符读入一个字符数组的一部分
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
//创建一个字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
//m1(isr);//一次读取一个字符
m2(isr);//一次读取一个字符数组
}
private static void m2(InputStreamReader isr) throws IOException {
//一次读取一个字符数组
//创建字符数组:长度:1024或者1024整数倍
char[] chs = new char[1024] ;
int len = 0;
while((len=isr.read(chs))!=-1) {
System.out.println(new String(chs,0,len));
}
//关闭资源
isr.close();
}
private static void m1(InputStreamReader isr) throws IOException {
//一次读取一个字符
int ch = 0;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
//关闭资源
isr.close();
}
}
5.3.1 Copy案例_字符流
需求:使用字符流进行操作,在当前项目下a.txt文件 (源文件)---->将内容复制到当前项目下的b.txt文件中(目的地)
public class CopyTest {
public static void main(String[] args) throws IOException {
//封装原文件 创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
//封装目的地 创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
//chars(isr, osw);
charArray(isr,osw);
//刷新流
osw.flush();
//释放资源
osw.close();
isr.close();
}
//一次读取一个字符数组
private static void charArray(InputStreamReader isr, OutputStreamWriter osw) throws IOException{
int len = 0;
char[] chs = new char[1024];
while((len = isr.read(chs))!= -1){
//写的操作
osw.write(chs,0,len);
}
}
//一次读取一个字符
private static void chars(InputStreamReader isr, OutputStreamWriter osw) throws IOException {
int ch = 0;
while((ch = isr.read()) != -1){
osw.write(ch);
}
}
}
5.4 字符节点流
简化代码书写操作:字符流的便捷类:FileReader和FileWriter
FileWriter:
- public void writer(String str):一次写入多个字符,将b数组中所有字符写入输出流;
FileReader:
- public int read(cahr[] c):将流中读取多个字符,将读到内容存入c数组中,返回实际读到的字符数;如果达到文件尾部,返回-1;
需求:将当前项目下的b.txt文件内容复制到当前目录copy.txt文件中
public class CopyTest {
public static void main(String[] args) throws IOException {
//封装源文件:b.txt
//创建字符输入流对象
FileReader fr = new FileReader("b.txt");
//封装目的地
FileWriter fw = new FileWriter("copy.txt");
//读写操作
char[] chs = new char[1024];
int len = 0 ;
while((len=fr.read(chs))!=-1) {
fw.write(chs, 0, len);
}
//刷新该流
fw.flush();
//关闭
fw.close();
fr.close();
}
}
5.5 close()和flush()方法的区别
close()
关闭资源,目的是释放跟系统相关的资源 ,一旦流关闭了,不能再给流中写入数据,否则会出现异常;
flush()
描述的刷新该流,将一些缓冲的字节进行写入(写入指定流中),在关闭流之前需要刷新字符流对象,仅仅刷新该流,刷新完毕之后依然可以写入数据;
5.6 字节流字符流
字节流
- 读:InputStream
- 写:OutputStream
字符流:
- 读:Reader
写:Writer
需要把磁盘上的文件内容展示控制台 (InputStream)
- 使用Java程序给磁盘上输出一个文件使用OutputStream
6. 字符缓冲流
字符流为了提高读写效率,在最基本的字符流的基础上,提供了字符缓冲流;
6.1 字符缓冲输出流
- BufferedWriter(Writer w):提供一个默认大小的缓冲区,字符输出流(足够大)
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//创建一个字符缓冲输出对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
//写数据
bw.write("hello");
bw.write("world");
bw.write("java");
//关闭流对象
bw.close();
}
}
6.2 字符缓冲输入流
- BufferedReader(Reader r):创建一个缓冲输入流对象,提供默认的缓冲区大小(足够大)
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
//创建一个缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
//一次读取一个数组
int len = 0;
char[] buffer = new char[1024];
while((len = br.read(buffer)) != -1){
System.out.println(new String(buffer,0,len));
}
//关闭资源
br.close();
}
}
6.3 字符缓冲流中的特有功能
BufferedReader:
- public String readLine() :一次读取一行内容,返回字符串内容,如果读完毕,则返回值为null
BufferedReader:
- public void newLine(): 写入一个行分隔符(新行):换行操作
public class BufferedDemo {
public static void main(String[] args) throws IOException {
write();
read();
}
//读的操作
private static void read() throws IOException {
//创建一个字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
//读数据:public String readLine() :
String line = null ;
while((line=br.readLine())!=null) {
System.out.println(line);
}
//释放资源
br.close();
}
//写的功能
private static void write() throws IOException {
//创建一个字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
for(int i = 0 ; i < 10 ; i ++) {
bw.write("hello"+i);
//针对字符缓冲输出流newLine()
bw.newLine();
bw.flush();
}
//关闭资源
bw.close();
}
}
6.4 Copy案例_字符缓冲流
需求:当前项目下a.java文件的内容----复制到当前下的b.java文件中
思路:
- BufferedReader 一次读取一个字符数组/一次读取一个字符 操作 a.java
- BufferedWriter :操作b.java文件 给文件中写内容
public class CopyDemo {
public static void main(String[] args) throws IOException {
method1() ;
method2() ;
}
//一次读取一行内容
private static void method2() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.java")) ;
BufferedWriter bw = new BufferedWriter(new FileWriter("b.java")) ;
//readLine()
String line = null ;
while((line=br.readLine())!=null) {
bw.write(line);
//一次写一行
bw.newLine();
//刷新
bw.flush();
}
//关闭资源
bw.close();
br.close();
}
//正常方法
private static void method1()throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("a.java")) ;
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("b.java")) ;
//一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=br.read(chs))!=-1) {
bw.write(chs, 0, len);
bw.flush();
}
//关闭资源
bw.close();
br.close();
}
}
7. 内存操作流
处理内存中的临时数据,比如变量;当前程序结束之后,这些数据就不存在了,程序结束,内存数据就消失了,不需要关闭资源;
ByteArrayOutputStream: 内存输出流,给内存中写入数据
- public ByteArrayOutputStream()
步骤:
- 创建ByteArrayOutputStream对象
- 写数据
ByteArrayInputStream: 内存输入流,将内存中的数据读出来
- public byte[] toByteArray() :通过内存操作输出流对象将内存中的数据转换成字节数组
- ByteArrayInputStream(byte[] byte)
步骤:
- 创建内存操作输入流对象
- 读数据:一次读取一个字节/一次读取一个字节数组
public class ByteArrayStream {
public static void main(String[] args) throws IOException{
//创建一个内存操作输出流对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//写数据
for(int i = 0; i < 10; i++){
//数据写到内存中
bos.write(("kaka" + i + "\t").getBytes());
}
//通过内存操作输出流对象将内存中的数据转换成字节数组
byte[] bytes = bos.toByteArray();
//创建内存操作输入流对象
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
//一次读一个字节
int by = 0;
while((by = bis.read()) != -1){
System.out.print((char)by);
}
}
}
8. PrintWriter流
封装了print()/ptintln()方法,后者支持写入后换行;
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
特点:
只能操作目的地文件,不能操作原文件
字符打印流: 可以实现自动刷新
public PrintWriter(Writer out,boolean autoFlush)
- 参数2:如果为true,开启自动刷新功能
比BufferedWriter更为方便;提供了println()打印后换行
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符打印流对象,不自动刷新
PrintWriter pw = new PrintWriter(new FileWriter("pw.txt"));
//写数据,换行
pw.println("hello");
pw.println("world");
pw.println("java");
//刷新流
pw.flush();
//关闭流
pw.close();
}
}
Copy案例_打印流
当前项目a.txt复制到c.txt文件中
public class PrintCopyTest {
public static void main(String[] args) throws IOException{
//封装源文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//封装目的地
PrintWriter pw = new PrintWriter(new FileWriter("c.txt"),true);
//读写操作
String line = null;
while((line = br.readLine()) != null){
pw.println(line);
}
//释放资源
pw.close();
br.close();
}
}
9. 键盘录入的另一种方法
使用BufferedReader(Reader in) :使用字符缓冲输入流的方式进行录入数据
- BufferedReader:利用字符缓冲输入流进行键盘录入(录入字符串居多:public String readLine())
public static void main(String[] args) throws IOException {
//录入字符串
//分步走
//创建一个字符缓冲 输入流对象
InputStream in = System.in ;
//创建一个基本的字符输入流对象
InputStreamReader isr = new InputStreamReader(in) ;
BufferedReader br = new BufferedReader(isr) ;
//一步走
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
System.out.println("请您输入一个字符串数据:");
String line = br.readLine() ; //读取一个行内容
System.out.println("您录入的字符串数据是:"+line);
//录入整数 int
//创建一个字符缓冲 输入流对象
BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in)) ;
System.out.println("请你输入一个整数数据:");
String str = br2.readLine() ;
int number = Integer.parseInt(str) ;
System.out.println(number);
}
10. 字节合并流
顾名思义就是将两个文件合并到一个文件中,继承自字节流;
10.1 合并两个文件
- public SequenceInputStream(InputStream s1, InputStream s2):将s1和s2合并
需求:
将a.txt以及b.txt的文件内容复制到 Copy.txt文件中
public class SequenceInputStreamDemo_01 {
public static void main(String[] args) throws IOException {
//封装a.txt文件和b.txt文件
InputStream s1 = new FileInputStream("a.txt");
InputStream s2 = new FileInputStream("b.txt");
//创建合并输入流对象
SequenceInputStream sis = new SequenceInputStream(s1,s2);
//封装目的地Copy.java
//创建一个字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.java")) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=sis.read(bytes))!=-1) {
bos.write(bytes, 0, len);
}
//释放资源
bos.close();
sis.close();
}
}
10.2 合并三个文件
- public SequenceInputStream(Enumeration<? extends InputStream> e):可以将两个以上的文件合并到一个流中
需求:
当前项目路径下的a.java , b.java,c.java三个文件的内容复制到d.java文件中
利用Enumeration:接口 Vector集合的特有迭代器(向量的枚举组件)
public class SequenceInputStreamDemo_02 {
public static void main(String[] args) throws IOException {
//Vector<InputStream>
//创建三个基本字节输入流对象
InputStream s1 = new FileInputStream("a.java");
InputStream s2 = new FileInputStream("b.java");
InputStream s3 = new FileInputStream("c.java");
//创建一个Vector集合
Vector<InputStream> ve = new Vector<InputStream>() ;
//添加到集合中
ve.add(s1);
ve.add(s2);
ve.add(s3);
//获取Enumeration:接口
Enumeration<InputStream> en = ve.elements();
//创建字节输入合并流对象
SequenceInputStream sis = new SequenceInputStream(en);
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d.java"));
//读写复制操作
byte[] bytes = new byte[1024];
int len = 0;
while((len=sis.read(bytes))!=-1) {
bos.write(bytes, 0, len);
}
//释放资源
bos.close();
sis.close();
}
}
11. 对象序列化
使用流传输对象的过程称为序列化、反序列化;序列化就是把对象写出到文件中;反序列化就是从文件中把对象读到程序里来;
序列化:将某个对象按照流的方式存入文本文件中或者在网络中传输
反序列化:将文本文件中流的数据或者网络中传输的数据还原成对象
11.1 对象流
ObjectOutputStream:写入OutputStream,输出流
- public final void writeObject(Object obj):将指定的对象写入流中
ObjectInputStream:读取(重构)对象
- public final Object readObject():将流读取为一个指定的对象
为了防止频繁的去更改类的成员(比如类的成员有很多),部分成员不想进行序列化,Java提供关键字transient
好处:
增强了缓冲区功能
增强了读写8种基本数据类型和字符串功能
增强了读写对象的功能:
- readObject():从流中读取一个对象;
- writeObject(Object obj):向流中写入一个对象
需求:使用序列化和反序列化来操作一个对象 (定义一个Person类)
public class Person implements Serializable {
/*
* 点击黄色警告线---->每次生产的SeriavalVersionUID产生一个固定的!
*/
private static final long serialVersionUID = 1L; //常量
private String name ;
//private int age;
private transient int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class ObjectStreamDemo {
public static void main(String[] args) throws Exception {
//序列化: 对象---->流数据
// write();
//反序列化
read() ;
}
private static void read() throws Exception{
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("oos.txt")) ;
// public final Object readObject():将流读取为一个指定的对象
Object obj = ois.readObject() ;
System.out.println(obj);
//关闭资源
ois.close();
}
private static void write() throws Exception {
//创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("oos.txt")) ;
//将指定的对象写入流中
//创建一个Person对象
Person p = new Person("高圆圆",30) ;
oos.writeObject(p);
//释放资源
oos.close();
}
}
注:
a) 必须实现Serializable接口;
b) 必须保证其所有属性均可序列化;
c) Transient修饰为临时属性,不参与序列化;
d) 读取到文件尾部标志:java.io.EOFException
12. Properties类
12.1 Properties概述
继承自Hashtable 表示一个持久的属性集,属性列表中每个键及其对应值都是一个字符串,有一些成员方法保存在流中或从流中加载;
特点:
- 不需要带泛型的
- 键和值都是字符串数据String
- 可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化设备中
使用Map集合的功能进行添加元素和遍历属性集合
public class PropertiesDemo {
public static void main(String[] args) {
//创建一个属性集合类对象
Properties prop = new Properties();
//利用Map集合的添加功能
prop.put("卡卡_01", "23");
prop.put("卡卡_02", "25");
prop.put("卡卡_03", "28");
//keySet() :获取所有的键的集合
Set<Object> set = prop.keySet() ;
for(Object key :set) {
//通过键获取值
Object value = prop.get(key);
System.out.println(key+"---"+value);
}
}
}
卡卡_03---28
卡卡_02---25
卡卡_01---23
12.2 属性集合类的特有功能
- public Object setProperty(String key,String value):添加元素
- public Set< String > stringPropertyNames():获取属性集合中所有的键的集合
- public String getProperty(String key):通过键获取对应的值
public class PropertiesDemo {
public static void main(String[] args) {
//创建一个属性集合类对象
Properties prop = new Properties();
//添加元素
prop.setProperty("卡卡", "小卡");
prop.setProperty("糖糖", "小糖");
prop.setProperty("安安", "小安");
//遍历
//获取属性集合中所有的键的集合
Set<String> set = prop.stringPropertyNames();
for(String key :set) {
//通过键获取值
String value = prop.getProperty(key) ;
System.out.println(key+"="+value);
}
}
}
12.3 流相关的应用(重要)
- public void store(Writer writer, String comments):将属性集合类中内容(键值对)保存在指定的文本文件中
- 参数1:指定的字符输出流
- 参数2:属性列表的描述:如果不指定,为null
- public void load(Reader reader):将指定的文本文件中内容加载到属性集合列表中
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
myStore();
// myLoad();
}
//将文本文件中的内容加载到属性集合类中
private static void myLoad() throws IOException {
//创建属性集合类对象
Properties prop = new Properties();
//将指定的文本文件中内容加载到属性集合列表中
FileReader fr = new FileReader("a.txt");
prop.load(fr);
//释放资源
fr.close();
System.out.println(prop);
}
//将属性集合中的列表数据保存到指定文本文件中
private static void myStore() throws IOException {
//创建属性集合类对象
Properties prop = new Properties();
//添加元素
prop.setProperty("卡卡_01", "23");
prop.setProperty("卡卡_02", "24");
prop.setProperty("卡卡_03", "26");
prop.setProperty("卡卡_04", "28");
//将属性集合类中内容(键值对)保存在指定的文本文件中
FileWriter writer = new FileWriter("name.txt");
prop.store(writer, "name list");
//释放资源
writer.close();
}
}
12.4 修改键对应的值
需求:
- 存在user.txt,文件中的内容以键值对存在 key=value,如果当前文件中存在"卡卡_02"键,需要将"卡卡_02"键对应的值更改为"100"
分析:
- user.txt文件内容加载到属性集合类中 Properites
- 遍历操作
- 判断键就是"卡卡_02",更改键对应的值 "100"
public class PropertiesTest {
public static void main(String[] args) throws IOException {
//创建属性集合类对象
Properties prop = new Properties() ;
//将user.txt文件中的内容加载进prop属性集合中
FileReader fr = new FileReader("user.txt") ;
prop.load(fr);
//释放资源
fr.close();
//遍历属性集合stringPropertyNames()
Set<String> set = prop.stringPropertyNames() ;
for(String key :set) {
//判断
if("卡卡_02".equals(key)) {
//更改当前key对应的值
prop.setProperty(key, "100") ;
break ;
}
}
//将属性集合中内容保存文本文件user.txt
FileWriter fw = new FileWriter("user.txt") ;
prop.store(fw, "name list");
//关闭资源
fw.close();
}
}
#name list
#Mon Jun 29 00:51:11 CST 2020
卡卡_04=28
卡卡_03=26
卡卡_02=100
卡卡_01=23