IO流
File类
File 文件和目录(文件夹)路径名的抽象表示。
构造方法
File(String pathname);//参数就是指定的路径/如果没有指定路径(默认是在当前项目下)
通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(File parent, String child);//从父抽象路径名和子路径名字符串创建新的 File实例。
File(String parent, String child);//参数1:父目录地址 参数2:具体的子文件地址
成员方法
创建/删除/重名
public boolean createNewFile() throws IOException :表示创建文件 :如果不存在,则创建
public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false
public boolean mkdirs():创建多个文件,如果父目录不存在,则创建
public boolean delete():删除文件或者文件夹(如果删除文件夹,文件夹必须为空目录)
public boolean renameTo(File dest):重命名
参数传递的修改的File对象
判断功能
public boolean canRead()是否可读
public boolean canWrite()是否可写
public boolean exists():是否存在
public boolean isFile():是否是文件
public boolean isDirectory():是否是文件夹
public boolean isHidden():是否隐藏
高级获取功能
public long length()
public String getName():获取抽象路径 名所表示的文件或者目录的名称
public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
需求:获取
D盘下的所有的文件夹以及文件的名称…
public class FileDemo2 {
public static void main(String[] args) {
//创建File对象,描述当前项目下的aaa.txt文件
File file = new File("aaa.txt") ;
System.out.println(file.canRead());
System.out.println(file.canWrite());
System.out.println(file.exists());
System.out.println(file.isDirectory());//false
System.out.println(file.isFile());
System.out.println(file.isHidden());
System.out.println(file.length());
System.out.println(file.getName());
System.out.println("------------------------");
// public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
//描述D盘
File file2 = new File("d://") ;
File[] fileArray = file2.listFiles();
//防止空指针异常
if(fileArray!=null){
for(File f :fileArray){
System.out.println(f.getName());
}
}
System.out.println("----------------------------------");
//public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
String[] strArray = file2.list();
if(strArray!=null){
for(String s:strArray){
System.out.println(s);
}
}
}
}
eg.1
需求:
将D:\EE_2106\day25\code路径下logo.jpg---->改名为 D:\EE_2106\day25\code路径下 mv.jpg
如果两个地址一样:只是改名
如果地址不一样,剪切并改名!
public class FileDemo {
public static void main(String[] args) throws IOException {
//表示:E盘下的demo文件夹中的a.txt文件
//File(String pathname) 方式1 (推荐)
// File file = new File("e://demo//a.txt") ;只是表示这个路径,如果创建a.txt文件,系统找不到指定路径
File file = new File("D:\\EE_2106\\day25\\code\\a.txt"); //绝对路径
File file2 = new File("aaa.txt");//没有带路径,就默认在当前项目下(相对路径)
File file3 = new File("D:\\EE_2106\\day25\\code\\demo") ;
File file4 = new File("aaa\\bbb\\ccc\\ddd") ;
//File(File parent, String child) 方式2
/* File file2 = new File("E://demo") ;
File file3 = new File(file2,"a.txt") ;
//File(String parent, String child):方式3
File file4 = new File("E://demo","a.txt") ;*/
// public boolean createNewFile()
System.out.println(file.createNewFile());
System.out.println(file2.createNewFile());
System.out.println(file3.mkdir());
System.out.println(file4.mkdirs());
System.out.println(file3.delete());
System.out.println(file.delete());
System.out.println("------------------------");
//D:\EE_2106\day25\code路径下logo.jpg :描述下这个地址File
// File srcFile = new File("D:\\EE_2106\\day25\\code\\logo.jpg") ;
File srcFile = new File("D:\\EE_2106\\day25\\code\\mv.jpg") ;
File destFile = new File("高圆圆.jpg") ;//当前项目路径下了
System.out.println(srcFile.renameTo(destFile)) ;
}
}
eg.2
需求2:
获取D盘下所有的以.jpg结尾的文件
分析:
1)描述下D盘
- public File[] listFiles():获取D盘下的所有的文件以及文件夹的File数组
2.1)对获取到的数组进行非判断,如果不为null,再去判断
2.2)判断File是一个文件
2.3)判断:文件必须以.jpg结尾。String类 endsWith(".jpg")提供了另一个重载功能
public File[] listFiles(FilenameFilter filter) String[] list(FilenameFilter filter) //参数为:文件名称过滤器FilenameFilter:接口
成员方法
boolean accept(File dir,String name);//测试指定文件是否包含在文件列表中 返回如果true,将文件添加到文件列表中
1)描述下D盘
2)public File[] listFiles(FilenameFilter filenamefilter):
获取D盘下的File数组的时候,就已经指定文件进行过滤…
import java.io.File;
import java.io.FilenameFilter;
public class IOtest01 {
public static void main(String[] args) {
File file = new File("e://");
File[] files1 = file.listFiles();
//方法一:
if (files1 != null) {
for (File f : files1) {
if (f.isFile()) {
if (f.getName().endsWith(".txt")) {
System.out.println(f);
}
}
}
}
System.out.println("————————————————");
//方法二:
File srcfile = new File("e://");
//获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤
//public File[] listFiles(FilenameFilter filter)
File[] files2 = srcfile.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
//返回true:表示将指定文件添加列表文件中
//描述文件所表示抽象路径File
File file1 = new File(dir, name);
//两个条件:file是文件并且file的文件名称以".jpg结尾"
return file1.isFile() && file1.getName().endsWith(".txt");
}
});
if (files2 != null) {
for (File f : files2) {
System.out.println(f.getName());
}
}
}
}
递归
方法递归
方法调用方法本身的一种现象,并非是方法嵌套方法
前提条件
1)必须有一个成员方法
2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归…
3)还存在一定的规律
注意事项
构造方法不存在递归
eg.1 5的阶乘
public class DiGuiDemo {
public static void main(String[] args) {
System.out.println("5的阶乘是:"+jieCheng(5));
}
//递归:需要考虑(一定要有规律)
private static int jieCheng(int i) {
if(i==1){
return 1 ;
}else{
return i * jieCheng(i-1) ;
}
}
}
eg.2 需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录。
public class DiGuiTest {
public static void main(String[] args) {
//描述D盘的demo文件夹
File srcFloder = new File("d://demo") ;//想删的文件夹地址
//调用递归删除的方法
deleteFloder(srcFloder) ;
}
public static void deleteFloder(File srcFloder) {
//获取srcFloder下的所有的文件以及文件的File数组
File[] fileArray = srcFloder.listFiles();
if(fileArray!=null){
for(File file:fileArray){
//获取到每一个file对象
//如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
if(file.isDirectory()){
deleteFloder(file) ;
}else{
//判断是文件,必须以.java结尾 文件
if(file.getName().endsWith(".java")){
//删除的同时----获取名称
System.out.println(file.getName()+"------------"+file.delete());
}
}
}
//删除文件夹
System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
}
}
}
InputStream&OutputStream
IO流的分类
按流的方向
输入和输出流
按类型分
字节和字符流:字节先出现,后面在有字符流
再次流的方向划分
字节输入流:InputStream:表示输入字节流的所有类的超类(父类)
字节输出流:OutputStream:表示字节输出流的所有类的超类
字符输入流:Reader表示输入字符流的抽象类
字符输出流:Writer表示输出字符流的抽象类
字节/字符流都很多子类
XXXInputStream
XXXOutputStream
XXXReader
XXXWriter
字节输出流
OutputStream抽象类
子类进行实例化FileOutputStream:将指定的内容写到文件中
实现步骤:
1)创建文件输出流对象 :
FileOutputStream(String name) :推荐:可以指定参数地址
FileOutputStream(File file)
2)写数据
public void write(int b) throws IOException 写一个字节
public void write(byte[] bytes) throws IOException 写一个字节数组
public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组
3)关闭资源
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//创建文件输出流对象
//指向某个盘符下的文件中(或者当前项目下)
FileOutputStream fos = new FileOutputStream("my.txt");//文件需要被创建当前项目下
//2)写数据
for (int x = 0; x < 10; x++) {
fos.write(("hello" + x).getBytes());
//windows操作系统 "\r\n"代表换换行
fos.write("\r\n".getBytes());
}
//3)关闭资源
fos.close(); //释放fos流对象所指向的my.txt的系统资源
}
}
在字节输出流中加入异常处理(捕获异常)
public class FileOutputStreamDemo2 {
public static void main(String[] args) {
// method1() ;
method2() ;//
}
//标准方式:try...catch...finally
//统一处理
private static void method2() {
FileOutputStream fos = null ;
//alt+ctrl+t--->
try {
fos = new FileOutputStream("fos2.txt") ;
//写数据
fos.write("hello,我来了".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//分别try...catch...(不用,这种方式阅读性很差)
private static void method1() {
//在当前项目下输出fos.txt
//创建字节输出流对象
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos.txt") ;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//写数据
try {
fos.write("hello,IO".getBytes()) ;
} catch (IOException e) {
e.printStackTrace();
}
//关闭资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
流的拷贝
字节输入流:InputStream
子类:FileInputStream
实现步骤:
需要读取当前项目下的fis.txt文件
1)创建文件字节输入流对象,指向 fis.txt
public FileInputStream(String name) throws FileNotFoundException
2)读内容
read(byte[] bytes):一次读取一个字节数组
read():一次读取一个字节
3)释放资源
读取文件的时候,一次读取一个字节,存在中文乱码, 在最终输出的结果 (char)by (场景:将某一个文件内容打印在控制台上了)
"abc" 英文 读一个字节 a--->97 b --98
针对中文字符: 现在idea环境: 编码格式:utf-8格式: 一个中文对应三个字节 ,和前面的英文拼接出现问题,只要中文都会乱码
因此才出现了字符流(加入编码和解码的格式)
public class FileInputStreamDemo {
public static void main(String[] args) {
//创建一个字节输入流对象
FileInputStream fis = null ;
try {
// fis = new FileInputStream("fis.txt") ;
fis = new FileInputStream("DiGuiTest.java") ; //读取当前项目下的DiGuiTest.java
//读取内容
/* //第一次读取
int by = fis.read(); //字节数
System.out.println(by);
System.out.println((char)by); //获取的字符
//第二次读取
by = fis.read();
System.out.println((char)by);
//第三次读取
by = fis.read() ;
System.out.println((char)by);
//第四次读取
by = fis.read() ;
System.out.println(by);//字节数
System.out.println((char)by);*/
//使用循环优化: 结束条件:获取的字节数为-1
//当前不知道循环多少次:while循环
//将判断,赋值一块去使用 (模板代码)
int by = 0 ; //字节数为0
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
读写复制操作:一次读取一个字节的方式
一次读取一个字节数组需求:
将当前项目下的DiGuiTest.java 的内容 复制到D盘下的Copy.java文件中
分析:
源文件: 当前项目下 “DiGuiTest.java”
封装源文件:FileInputStraem(String pathname)一次读取一个字节
目的地文件: D://Copy.java
封装目的地文件:FileOutputStream(String pathname)一次写一个字节
public class CopyFileDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis() ;//时间毫秒值
// method("DiGuiTest.java","D://Copy.java") ;
method2("DiGuiTest.java","D://Copy.java") ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒");
}
private static void method2(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
// 封装源文件:FileInputStraem(String pathname)
//字节输入流
fis = new FileInputStream(srcFile) ;
//字节输出流
// 封装目的地文件:FileOutputStream(String pathname)
fos = new FileOutputStream(destFile) ;
//读写复制操作
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
//赋值
//fos流对象中写
//带上len的使用
fos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 一次读取一个字节:读写复制
* @param srcFile 源文件
* @param destFile 目的地文件
*/
private static void method(String srcFile, String destFile) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
// 封装源文件:FileInputStraem(String pathname)
//字节输入流
fis = new FileInputStream(srcFile) ;
//字节输出流
// 封装目的地文件:FileOutputStream(String pathname)
fos = new FileOutputStream(destFile) ;
//读写复制操作
//一次读取一个字节
int by = 0 ;
while((by=fis.read())!=-1){
//没有读完,继续复制 :写一个字节
fos.write(by);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public int read(byte[] b)throws IOException//一次读取一个字节数组,返回值值的是每次读取的实际字节数
需求:将fis2.txt读取出来,并展示在控制台上
public class FileInputStreamDemo2 {
public static void main(String[] args) {
//创建字节输入流对象
FileInputStream fis = null ;
try {
fis = new FileInputStream("fis2.txt") ;
//创建一个数组:长度:1024或者1024的整数倍
byte[] buffer = new byte[1024] ; //长度虽然1024个长度
int len = 0 ;
while((len=fis.read(buffer))!=-1){
//每次获取的从0开始获取实际字节长度
System.out.println(new String(buffer,0,len)) ;
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字节流
字符流和字节流读取文件的方式
import java.io.*;
public class BufferedTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
Copy1("srcFile","destFile");
Copy2("srcFile","destFile");
Copy3("srcFile","destFile");
Copy4("srcFile","destFile");
long end = System.currentTimeMillis();
System.out.println("本次共运行了"+(end-start)+"毫秒");
}
//基本的字节流一次读取一个字节
public static void Copy1(String srcFile,String destFile)throws IOException{
FileInputStream fis = null;
FileOutputStream fos = null;
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
int by = 0;
while((by=fis.read())!=-1){
fos.write(by);
}
fos.close();
fis.close();
}
//基本的字节流一次读取一个字节数组
public static void Copy2(String srcFile,String destFile)throws IOException{
FileInputStream fis = null;
FileOutputStream fos = null;
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] bytes = new byte[1024];
int len = 0;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
//缓冲流一次读取一个字节
public static void Copy3(String srcFile,String destFile)throws IOException{
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
bis = new BufferedInputStream(new FileInputStream(srcFile));
bos = new BufferedOutputStream(new FileOutputStream(destFile));
int by = 0;
while((by=bis.read())!=-1){
bos.write(by);
}
bos.close();
bis.close();
}
//缓冲流一次读取一个字节数组
public static void Copy4(String srcFile,String destFile)throws IOException{
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
bis = new BufferedInputStream(new FileInputStream(srcFile));
bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bytes = new byte[1024];
int len = 0;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
}
}
字符流
Reader/Writer子类:转换流
InputStreamReader(InputStream in);
OutputStreamWriter(OutputStream out);
//他们不能直接去操作文件,jdk提供了这两种类型的便捷类,可以直接操作文件
FileReader(File file);
FileReader(String pathname);
FileWriter(File file);
FileWriter(String filename);
//这两个类:使用的平台的默认编码和解码 (utf-8)
Reader:抽象类
具体的子类:字符转换输入流 InputStreamReader
构造方法
InputStreamReader(InputStream in) ;//使用平台默认解码集进行读
InputStreamReader(InputStream in,String charset) ;//使用指定的解码集进行读
字符流的出现是在字节流的后面,可以解决中文乱码问题
Writer:抽象类
提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!
构造方法
OutputStreamWriter(OutputStream out) ;//使用平台默认编码集写入数据
OutputStreamWriter(OutputStream out, String charsetName) ;//使用指定的字符集进行编码 写入数据
import java.io.*;
public class Reader_WriterTest01 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IO操作\\c.txt"));
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IO\\c3.txt"));
char[] chars = new char[1024];
int len = 0;
while((len = isr.read(chars))!=-1){
osw.write(chars,0,len);
System.out.println(new String(chars,0,len));
osw.flush();
}
osw.close();
isr.close();
}
}
asdasdas
asdasd
sfdsdg
adas
as11223
aassa
asda
s2121
public class Reader_WriterTest02 {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\千锋\\IO\\c4.txt"));
String s = "12345643213224";
char[] chars =s.toCharArray();
osw.write(chars);
osw.flush();
osw.close();
}
}
BufferedReaer/BufferedWriter :读写复制操作
一次读取一个字符
一次读取一个字符数组
特有功能
利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行
一个文本文件读写复制:
阻塞流 (传统的IO流)
当一个线程如果操作的是读的动作,read(byte[] byte/char[] ..)/readLine():都属于阻塞式方法
另一个线程如果操作的是写的动作,读的线程如果开始读,这边写的线程才能开始进行写的复制操作!
基本的字节流:一次读取一个字节/一次读取一个字节数组
字节缓冲流:一次读取一个字节/一次读取一个字节数组
字符转换流:
InputStreamReader(InputStream in)
OutputStreamWriter(OutputStream out)
一次读取一个字符/一次读取一个字符数组
转换流的便捷类
FileReader(String name)
FileWriter(String writer)
一次读取一个字符/一次读取一个字符数组
BufferedReader
BufferedWriter
一次读取一个字符/一次读取一个字符数组
特有功能:
一次读取一行内容
BufferedReader:字符缓冲输入流
BufferedReader键盘录入数据
Scanner(InputSteram in)、String nextLine()
BufferedReader(Reader in);InputStreamReader(InputStream in);//转换流
如果直接进行读的操作(直接操作文件)FileReader(String pathName)
创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int size):指定缓冲区大小
特有功能:
public String readLine() :一次读取一行内容
BufferedWriter:字符缓冲输出流
BufferedWriter(Writer out) :创建默认的缓冲区大小: 默认大小:defaultcharbuffersize:8192(默认值足够大)
BufferedWriter(Writer out, int sz) :指定的大小
public void newLine() throws IOException:写入行的分隔符号
BufferedReaer/BufferedWriter :读写复制操作
一次读取一个字符
一次读取一个字符数组
特有功能:
利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行
eg.将当前项目下的ReaderDemo.java复制到当前项目下:copy.java
import java.io.*;
//一次读取一行
public class Reader_WriterTest03 {
public static void main(String[] args) throws IOException {
BufferedReader br = null;
BufferedWriter bw = null;
br = new BufferedReader(new FileReader("D:\\IO操作\\c.txt"));
bw = new BufferedWriter(new FileWriter("D:\\IO\\c5.txt"));
String line = null;
while((line = br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
合并流
SequenceInputStream:
构造方法
public SequenceInputStream(InputStream s1,InputStream s2)//参数1和参数2:分别要读取的字节输入流对象
public SequenceInputStream(Enumeration<? extends InputStream> e) ;//将两个以上的文件进行读取
Vector<InputStream>add//(添加多个字节输入流对象)
eg.
public class SequenceTest {
public static void main(String[] args) throws IOException{
InputStream isr1 = new FileInputStream("D:\\IO\\c1.txt");
InputStream isr2 = new FileInputStream("D:\\IO\\c2.txt");
InputStream isr3 = new FileInputStream("D:\\IO\\c3.txt");
InputStream isr4 = new FileInputStream("D:\\IO\\c4.txt");
InputStream isr5 = new FileInputStream("D:\\IO\\c5.txt");
Vector<InputStream> vector = new Vector();
vector.add(isr1);
vector.add(isr2);
vector.add(isr3);
vector.add(isr4);
vector.add(isr5);
//public Enumeration<E> elements() ---- >类似于Collection的Iterator迭代器
Enumeration<InputStream> enumeration = vector.elements();
//创建合并流对象 封装源文件
SequenceInputStream sis = new SequenceInputStream(enumeration);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\IO\\c.txt"));
int b = 0;
while((b = sis.read())!=-1){
bos.write(b);
bos.flush();
}
bos.close();
sis.close();
}
}
序列化&反序列化
序列化
ObjectOutputStream
将某个实体对象写入到流对象中---->将一个对象变成流数据
构造方法
protected ObjectOutputStream()
protected ObjectOutputStream(OutputStream out) :将某个对象通过底层的基本字节输出进行写的动作
public final void writeObject(Object obj) throws IOException
反序列化
ObjectInputStream
将流数据----还原成 “对象”
构造方法
public ObjectInputStream(InputStream in)
public final Object readObject()
throws IOException, ClassNotFoundException
java.io.NotSerializableException: com.qf.serailizable_05.Person
NotSerializableException:未实现序列化接口的异常
一个类在进行序列化的时候,(将类的对象写入序列化流中),标记接口Serializable 它有个特点为当前这个Person进行编码(为类以及类的成员----->序列化化版本ID(签名):SerialversonUID)java.io.InvalidClassException: com.qf.serailizable_05.Person; local class incompatible:stream classdesc serialVersionUID = 2588921225545403990,local class serialVersionUID = -862808041229244683
在进行序列化的时候:当前的serialVersionUID:序列化版本id号 (假设100):内存中生成一个id值
在进行反序列化的时候:将流指向对象:Person类的字段信息更改了(类的签名信息就会被更改),那么直接进行反序列化产生的serialVersionUID=(假设200)
两个序列ID不一样
序列化版本id保证,在idea中生成一个固定的序列版本id号 (一般都针对实体类)
一个实体类:
1)当前类必须为具体类 class 类名{}
2)必须存在私有字段(私有成员变量)
3)必须提供公共的setXXX()/getXXX()
4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable
idea—>file—>setting---->editor---->Inspections----->java---->序列化serializion issue—>serializable class 打上对钩即可!
需求:将Person p = new Person(“高圆圆”,42) ;---->变成流对象 进行传输
import java.io.Serializable;
public class Person implements Serializable {
//产生一个固定的序列化版本Id
private static final long serialVersionUID = 8988325735017562383L; //常量值
String name;
int age; //transient:想让某个字段不参与序列化:这个字段(成员变量就使用transient)
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
myWriter();
myReader();
}
//序列化
public static void myWriter() throws IOException {
//创建Person对象
Person person = new Person("老大", 12);
//protected ObjectOutputStream(OutputStream out):创建一个序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IO操作\\a.txt"));
//将p对象写入到oos流对象中
//public final void writeObject(Object obj)throws IOException
oos.writeObject(person);
//释放资源
oos.close();
}
//反序列化
public static void myReader() throws IOException, ClassNotFoundException {
//创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IO操作\\a.txt"));
//读
//public final Object readObject()
Object o = ois.readObject();
//关闭流
ois.close();
System.out.println(o);
}
}
Person{name='老大', age=12}
Properties
概念
Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String
表示一组持久的属性。 Properties可以保存到流中或从流中加载。
属性列表中的每个键及其对应的值都是一个字符串。
1)可以使用Map的功能
put(K ,V)
遍历:keySet()通用
2)有自己特有功能添加元素和遍历
public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
public Set<String> stringPropertyNames():获取属性列表中的所有的键
public String getProperty(String key):在属性列表中通过键获取值
Propeties:键和值都是字符串类型:可能需要在src(类所在的路径:类路径)
作为一个配置文件
将字节输入流或者字符输入中所在的文件中的内容加载属性列表中
void load(Reader reader) void load(InputSteram in)
将Properties里面存储的内容,保存到某个目录的xxx配置文件中保存
public void store(Writer writer,String comments) public void store(OutputStream out,String comments)
将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中
eg.1
import java.util.Properties;
import java.util.Set;
public class PropertiesTest01 {
public static void main(String[] args) {
//Properties() :空参构造
Properties properties = new Properties();
// System.out.println(properties);
//利用Map集合的功能去添加元素
properties.put("高圆圆", "赵又廷");
properties.put("文章", "姚笛");
properties.put("文章", "马伊琍");
properties.put("王宝强", "马蓉");
// System.out.println(properties);
//遍历
Set<Object> keySet = properties.keySet();
for (Object key : keySet) {
//通过key获取value
Object value = properties.get(key);
System.out.println(key + "---" + value);
}
System.out.println("---------------------------------------");
//创建一个空的属性列表
Properties prop = new Properties();
prop.setProperty("张三", "30");
prop.setProperty("李四", "40");
prop.setProperty("王五", "35");
prop.setProperty("赵六", "45");
//遍历:
Set<String> set = prop.stringPropertyNames();//获取所有键
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key + "---" + value);
}
}
}
高圆圆---赵又廷
王宝强---马蓉
文章---马伊琍
---------------------------------------
赵六---45
王五---35
张三---30
李四---40
eg.2
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;
public class PropertiesTest02 {
public static void main(String[] args) throws IOException{
myStore();
myLoad();
}
//将属性集合类中的内容--保存到指定文件汇中
public static void myStore()throws IOException{
Properties prop = new Properties();
//添加key和value
prop.setProperty("张三丰","56");
prop.setProperty("吴奇隆","60");
prop.setProperty("成龙","65");
prop.setProperty("刘德华","70");
//public void store(Writer writer,String comments):
//参数2:给当前属性列表中加入一个描述
//保存指定的文件中
prop.store(new FileWriter("D:\\IO操作\\d.txt"),"text01");
System.out.println("保存完毕!");
}
//加载:需要将names.txt文件加载到属性列表中
public static void myLoad()throws IOException{
//创建一个空的属性列表
Properties prop = new Properties();
System.out.println(prop);
//读取src路径下的names.properties
//1.获取当前类所在的字节码文件对象
Class clazz = PropertiesTest02.class;
//2.获取当前类所在的类加载器Class:public ClassLoader getClassLoader()
ClassLoader classLoader = clazz.getClassLoader();
//3.在类加载器中,获取当前资源文件(配置文件names.proprites)所在的输入流对象
//public InputStream getResourceAsStream(String name)
//text01.properties必须在src目录下
InputStream ism = classLoader.getResourceAsStream("text01.properties");
//将inputStream加载到属性集合类中 void load(InputStream in)
prop.load(ism);
System.out.println(prop);
//遍历
Set<String> set = prop.stringPropertyNames();
for(String s: set){
String value = prop.getProperty(s);
System.out.println(s+"--"+value);
}
}
}
保存完毕!
{}
{liso=70, zhangsan=65, liuwu=56, dada=60}
liso--70
zhangsan--65
liuwu--56
dada--60
IO流总结
I0流原理及流的分类
Java IO流原理
1.I/O是Input/Output的缩写,I/O技术是非常实用的技术, 用于处理数据传输。如读/写文件,网络通讯等。
2.Java程序中, 对于数据的输入/输出操作以"流(stream)”的方式进行。
3.java.io包 下提供了各种"流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。
4.输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
5.输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。
流的分类
按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件
按数据流的流向不同分为:输入流,输出流
按流的角色的不同分为:节点流,处理流/包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
FileReader 和FileWriter介绍
FileReader和FileWriter是字符流,即按照字符来操作io
FileReader相关方法:
1) new FileReader(File/String)
2) read:每次读取单个字符,返回该字符,如果到文件末尾返回-1
3) read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1
相关API:
1) new String(char[):将char[]转换成String
2) new String(charD.off,len):将char[]的指定部分转换成String
FileWriter常用方法
1) new FileWriter(File/String):覆盖模式,相当于流的指针在首端
2) new FileWriter(File/String.true):追加模式,相当于流的指针在尾端
3) write(int):写入单个字符
4) write(char[]):写入指定数组
5) write(char[],off,len):写入指定数组的指定部分
6) write (string) :写入整个字符串
7) write(string,off,len):写入字符串的指定部分
相关API:
String类: toCharArray:将String转换成char[]
注意:
FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!
节点流和处理流
节点流和处理流的区别和联系
1.节点流是底层流/低级流,直接跟数据源相接。
2.处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。[源码理解]。
3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]。
处理流的功能主要体现在以下两个方面:
1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
2.操作的便捷:处理流可能提供了一系列便捷的方法来次输入输出大批量的数据, 使用更加灵活方便。
对象流-ObjectlnputStream和ObjectOutputStream
1.将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件中直接恢复int 100
2.将Dog dog = new Dog(”小黄”, 3)这个dog对象保存到文件中,并且能够从文件恢复.
3.上面的要求, 就是能够将基本数据类型或者对象进行序列化和反序列化操作
序列化和反序列化
-
序列化就是在保存数据时,保存数据的值和数据类型
-
列化就是在恢复数据时,恢复数据的值和数据类型
-
需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
Serializable / 这是一个标记接口
Externalizable
注意事项和细节说明
1)读写顺序要一致
2)要求实现序列化或反序列化对象,需要实现Serializable
3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
5)序列化对象时,要求里面属性的类型也需要实现序列化接口
6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
标准输入输出流
System.in标准输入 | InputStream | 键盘 |
---|---|---|
System.out标准输出 | OutPutStream | 显示器 |
转换流
InputStreamReader
OutputStreamWriter