首页 > 编程语言 >Java——I/O流

Java——I/O流

时间:2022-12-26 21:34:39浏览次数:37  
标签:java new io import Java public out


文章目录

  • ​​一. I/O流概述​​
  • ​​二. I/O流的分类​​
  • ​​三. 流应该怎么学习​​
  • ​​四. IO流四大家族​​
  • ​​五. 需要掌握的流​​
  • ​​1. java.io.FileInputStream常用方法​​
  • ​​2. java.io.FileOutputStream常用方法​​
  • ​​3. 文件的复制原理​​
  • ​​4. java.io.FileReader​​
  • ​​5. java.io.FileWriter​​
  • ​​6. java.io.BufferedReader​​
  • ​​7. java.io.BufferedWriter​​
  • ​​8. java.io.DataOutputStream​​
  • ​​9. java.io.DataInputStream​​
  • ​​10. java.io.PrintStream​​
  • ​​11. java.io.ObjectOutputStream​​
  • ​​1. 对象的序列化和反序列化​​
  • ​​2. transient关键字​​
  • ​​3. 关于序列化版本号​​
  • ​​六. java.io.File类​​
  • ​​1. File类的常用方法​​
  • ​​2. 拷贝目录​​
  • ​​七. IO和Properties联合使用​​

一. I/O流概述

Java——I/O流_数组


通过IO可以完成硬盘的读和写

二. I/O流的分类

按照流的方向进行分类:以内存为参照物

  • 往内存中去,叫做输入。或者叫读
  • 从内存中出来,叫做输出,或者叫写

按照读取数据方式不同进行分类

  • 有的流是按照字节方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位,这种流是万能的,什么类型的文件都可以读取。包括:文本、声音、视频、图片…
假设文件file.txt,采用字节流的话是这样读的:
a中国bc张三fe
第一次读:一个字节,正好读到'a'
第二次读:一个字节,正好读到'中'字符的一半
  • 有的流是按照字符的方式读取数据,一次读取1个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取
假设文件file.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读:'a'字符('a'字符在windows系统中占用1个字节)
第二次读:'中'字符('中'字符在Windows系统中占用2个字节)

三. 流应该怎么学习

Java中IO流都已经写好了,程序员不需关心,主要掌握在Java中提供了哪些流,每个流的特点,常用方法

  • java流都是在java.io.*下

四. IO流四大家族

java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流

四大家族的首领都是抽象类(abstract class)

  • 所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法,流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费很多资源
  • 注意:在java中只要’'类名"以Stream结尾的都是字节流,以"Reader/Writer"结尾的都是字符流
  • 所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法,养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下,这个刷新表示将管道当中剩余未输出的数据强行输出完(清空管道)刷新的作用就是清空管道,没有flush可能会导致丢失数据

五. 需要掌握的流

java.io包下需要掌握的流16个

文件专属

  • java.io.FileInputStream
  • java.io.FileOutputStream
  • java.io.FileReader
  • java.io.FileWriter

转换流(将字节流转换成字符流)

  • java.io.InputStreamReader
  • java.io.OutputStreamWriter

缓存流专属:

  • java.io.BufferedReader
  • java.io.BufferedWriter
  • java.io.BufferedInputStream
  • java.io.BufferedOutputStream

数据流专属:

  • java.io.DataInputStream
  • java.io.DataOutputStream

标准输出流:

  • java.io.PrintWriter
  • java.io.PrintStream

对象专属流:

  • java.io.ObjectInputStream
  • java.io.ObjectOutputStream

1. java.io.FileInputStream常用方法

  • 文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
  • 字节的方式,完成输入的操作,完成读的操作(硬盘—>内存)
package com.pudding;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建文件字节输入流对象
//以下采用绝对路径
fis = new FileInputStream("D:\\IDEA\\temp");

//开始读
int readData = fis.read(); //这个方法的返回值是:读取到的"字节"本身
System.out.println(readData); //97

readData = fis.read();
System.out.println(readData); //98

readData = fis.read();
System.out.println(readData); //99

readData = fis.read();
System.out.println(readData); //100

readData = fis.read();
System.out.println(readData); //101

readData = fis.read();
System.out.println(readData); //102

//已经读到文件末尾了,再读的时候读取不到任何数据,返回去-1
readData = fis.read();
System.out.println(readData); //-1

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//finally语句块当中确保流一定关闭
//关闭流的前提是:流不为空。流是空的时候没必要关闭
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
}
package com.pudding;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
对第一个程序进行改进,循环方式

分析这个程序的缺点:
一次读写一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面
能不能一次读写多个字节呢
*/
public class FileInputStreamTest02 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\IDEA\\temp");

/*while (true) {
int readData = fis.read();
if (readData == -1) {
break;
}
System.out.println(readData);
}*/

//改造while循环
int readData = 0;
while ((readData = fis.read()) != -1) {
System.out.println(readData);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

97
98
99
100
101
102

进行改进,使用如下方法:

  • int read(byte[] b)
一次最多读取b.length个字节
减少硬盘和内存的交互,提高程序的执行效率
往byte[]数组中读
package com.pudding;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest03 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//相对路径一定是从当前位置作为起点开始找的
//IDEA默认当前的路径是:工程Project的根就是IDEA的默认当前路径
//fis = new FileInputStream("tempfile");
fis = new FileInputStream("IO流/src/tempfile2");

//开始读,采用byte数组,一次读取多个字节,最多读取"数组.length"个字节
byte[] bytes = new byte[4]; //准备一个长度为4的byte数组,一次最多读取4个字节
//这个方法的返回值是:读取到的字节数量,不是字节本身
int readCount = fis.read(bytes);//第一次读到4个字节
System.out.println(readCount); //4
//将byte数组全部转换为字符串
//System.out.println(new String(bytes));//abcd
//不应该全部转换,应该读取多少个字节,转换多少个
System.out.println(new String(bytes,0,readCount)); //abcd


readCount = fis.read(bytes); //第二次只能读到2个字节
System.out.println(readCount);//2
//将byte数组全部转换为字符串
System.out.println(new String(bytes));//efcd
//不应该全部转换,应该读取多少个字节,转换多少个
System.out.println(new String(bytes,0,readCount)); //ef

readCount = fis.read(bytes); //一个字节都没有读到返回-1
System.out.println(readCount);//-1



} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

最终版

package com.pudding;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
最终版本
*/
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("IO流/src/tempfile2");
//准备一个byte数组
byte[] bytes = new byte[4];
/*while (true) {
int readCount = fis.read(bytes);
if (readCount == -1) {
break;
}
//把byte数组转换为字符串
System.out.print(new String(bytes,0,readCount)); //abcdef
}*/

int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
System.out.println(new String(bytes,0,readCount));
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

FileInputStream类的其他常用方法:

  • int available():返回流当中剩余没有读到的字节数量
  • long skip(long n):跳过几个字节不读
package com.pudding;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamTest05 {
public static void main(String[] args) {
FileInputStream fis = null;

try {
fis = new FileInputStream("IO流/src/tempfile2");
System.out.println("总字节数量:"+fis.available()); //6
/*
//读一个字节
int readByte = fis.read();
//还剩下可以读的字节数量:5
System.out.println("剩下多少字节没有读:"+fis.available());

//这个方法的用处?
byte[] bytes = new byte[fis.available()]; //不适合大文件,因为byte[]不能太大
//不需要循环了。读一次即可
int readCount = fis.read(bytes); //6
System.out.println(new String(bytes)); //abcdef
*/

//skip跳过去几个字节不读取,以后会用
fis.skip(3);
System.out.println(fis.read()); //100

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
}

2. java.io.FileOutputStream常用方法

文件字节输出流,负责写
从内存到硬盘

package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
/*
//这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入
fos = new FileOutputStream("IO流/src/myfile");
*/

//以追加的方式在文件末尾写入,不会清空原文件
fos = new FileOutputStream("IO流/src/myfile",true);
//开始写
byte[] bytes = {97,98,99,100};
//将byte数组全部写出
fos.write(bytes); //abcd
//将byte数组的一部分写出
fos.write(bytes,0,2); //在写ab

//字符串
String s = "hello world";
//将字符串转换为byte数组
byte[] bs = s.getBytes();
fos.write(bs);

//写完之后,最后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
}

3. 文件的复制原理

  • 使用FileInputStream + FileOutputStream完成文件的拷贝
  • 拷贝的过程应该是一边读,一边写
  • 使用以上的字节流拷贝文件的时候,文件类型随意,万能的,什么样的文件都能拷贝

Java——I/O流_System_02

package com.pudding;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Copy01 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建一个输入流对象
fis = new FileInputStream("IO流/src/myfile");
//创建一个输出流对象
fos = new FileOutputStream("IO流/src/com/pudding/myfile");

//最核心的,一边读,一边写
byte[] bytes = new byte[1024*1024]; //1MB
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}

//刷新,输出流最后要刷新
fos.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//要分开try,一起try的时候,其中一个出现异常,可能会影响到另一个流的关闭
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

4. java.io.FileReader

  • 文件字符输入流,只能读取普通文本
  • 读取文本内容时,比较方便
package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest {
public static void main(String[] args) {
FileReader reader = null;
try {
//创建文件字符输入流
reader = new FileReader("IO流/src/tempfile2");
//开始读
char[] chars = new char[4]; //一次读取4个字符
int readCount = 0;
while ((readCount = reader.read(chars)) != -1) {
System.out.print(new String(chars,0,readCount)); //abcdef
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
}

使用FileReader、FileWriter进行拷贝的话,只能拷贝普通文本文件

package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Copy02 {
public static void main(String[] args) {
FileReader in = null;
FileWriter out = null;
try {
//负责读
in = new FileReader("IO流/src/com/pudding/Copy02.java");
//负责写
out = new FileWriter("Copy02.java");

//一边读一边写
char[] chars = new char[1024*512];
int readCount = 0;
while ((readCount = in.read(chars)) != -1) {
out.write(chars,0,readCount);
}

//刷新
out.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

}
}

5. java.io.FileWriter

  • 文件字符输出流,写
  • 只能输出普通文本
package com.pudding;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
public static void main(String[] args) {
FileWriter out = null;
try {
//创建文件字符输出流对象
out = new FileWriter("file");

//开始写
char[] chars = {'我','是','中','国','人'};
out.write(chars);
out.write(chars,2,3);
out.write("我是一名Java软件工程师");
out.write("\n");
out.write("hello,world");

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

6. java.io.BufferedReader

  • 带有缓冲区的字符输出流
  • 使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓存
package com.pudding;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class BufferedReaderTest01 {
public static void main(String[] args) throws Exception {
FileReader reader = new FileReader("Copy02.java");
//当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
//外部负责包装的这个流,叫做:包装流,还有一个名字:处理流
//像当前的这个程序来说:FileReader就是一个节点流。BufferedReader就是包装流/处理流
BufferedReader br = new BufferedReader(reader);

//读一行
/*String firstLine = br.readLine();
System.out.println(firstLine);

String secondLine = br.readLine();
System.out.println(secondLine);*/

//br.readLine()读取一整行,但是不带换行符
String s = null;
while ((s = br.readLine()) != null) {
System.out.println(s);
}

//关闭流
//对于包装流来说,只需要关闭最外层流就行,里面的节点流会自动关闭
br.close();
}
}

转换流:InputStreamReader

package com.pudding;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;

public class BufferedReaderTest02 {
public static void main(String[] args) throws Exception {
/*
//字节流
FileInputStream in = new FileInputStream("Copy02.java");

//通过转换流转换(将字节流转换成字符流)
//in是节点流,reader是包装流
InputStreamReader reader = new InputStreamReader(in);

//这个构造方法只能传一个字符流,不能传字节流
//reader是节点流,br是包装流
BufferedReader br = new BufferedReader(reader);
*/
//合并
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("Copy02.java")));

String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}

//关闭
br.close();
}
}

7. java.io.BufferedWriter

  • 带有缓冲的字符输出流
  • 转换流:OutputStreamWriter
package com.pudding;

import java.io.*;

public class BufferedWriterTest {
public static void main(String[] args) throws Exception {
//带有缓冲区的字符输出流
//BufferedWriter out = new BufferedWriter(new FileWriter("copy"));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy2.java",true)));

//开始写
out.write("hello world");
out.write("\n");
out.write("pudding");
//刷新
out.flush();
//关闭
out.close();
}
}

8. java.io.DataOutputStream

  • java.io.DataOutputStream是数据专属流
  • 这个流可以将数据连同数据的类型一并写入文件
  • 注意:这个文件不是普通文本文档(记事本打不开)
package com.pudding;

import java.io.DataOutputStream;
import java.io.FileOutputStream;

public class DataOutputStreamTest {
public static void main(String[] args) throws Exception {
//创建数据专属的字节输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data"));
//写数据
byte b = 100;
short s = 200;
int i = 300;
long l = 400L;
float f = 3.0F;
double d = 3.14;
boolean sex = false;
char c = 'a';
//写
dos.writeByte(b); //把数据以及数据的类型一并写入文件当中
dos.writeShort(s);
dos.writeInt(i);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeBoolean(sex);
dos.writeChar(c);

//刷新
dos.flush();;
//关闭最外层
dos.close();

}
}

9. java.io.DataInputStream

  • java.io.DataInputStream是数据字节输入流
  • DataInputStream写的文件,只能使用DataInputStream去读,并且读的时候你需要提前知道写的顺序
  • 读的顺序需要和写的顺序一致,才可以正常取出数据
package com.pudding;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class DataInputStreamTest01 {
public static void main(String[] args) throws Exception {
DataInputStream dis = new DataInputStream(new FileInputStream("data"));
//开始读
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
boolean sex = dis.readBoolean();
char c = dis.readChar();

System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(sex);
System.out.println(c);

dis.close();
}
}

10. java.io.PrintStream

  • 标准的字节输出流,默认输出到控制台
package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

public class PrintStreamTest {
public static void main(String[] args) throws Exception {
//联合起来写
System.out.println("hello world");

//分开写
PrintStream ps = System.out;
ps.println("pudding");
ps.println("zhangsan");

//标准输出流不需要手动关闭

//可以改变标准输出流的输出方向
/*
之前System类使用过的方法和属性

System.gc();
System.arraycopy();
System.currentTimeMillis();
System.exit(0);
PrintStream ps2 = System.out;
*/

//标准输出流不再指向控制台,指向"log"文件
PrintStream printStream = new PrintStream(new FileOutputStream("log"));
//修改输出方向,将输出方向修改到log文件
System.setOut(printStream);
//再输出
System.out.println("hello world");
}
}
package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
日志工具
*/
public class Logger {
//记录日志的方法
public static void log(String msg) {
PrintStream out = null;
try {
//指向一个日志文件
out = new PrintStream(new FileOutputStream("log.txt"));
//改变输出方向
System.setOut(out);
//日期当前时间
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(nowTime);

System.out.println(strTime + ":" +msg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

}
}


package com.pudding;

public class LogTest {
public static void main(String[] args) {
//测试工具类是否好用
Logger.log("调用了System类的gc()方法,建议启动垃圾回收");
Logger.log("用户尝试登录");
}
}

11. java.io.ObjectOutputStream

1. 对象的序列化和反序列化

Java——I/O流_System_03

  • 序列化:Java对象存储到文件中。将java对象的状态保存下来的过程
  • 反序列化:将硬盘上的数据重新恢复到内存当中,恢复成java对象

参与序列化和反序列化的对象,必须实现Serializable接口

注意:通过源代码发现,Serializable接口只是一个标志接口:

public interface Serializable {
}
这个接口当中什么代码也没有
起到一个标识的作用,Java虚拟机看到这个类实现的接口,可能会对这个类进行特殊处理,Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号
package bean;

import java.io.Serializable;

public class Student implements Serializable {

//Java虚拟机看到Serializable接口会自动生成一个序列化版本号
private int no;
private String name;

public Student() {
}

public Student(int no, String name) {
this.no = no;
this.name = name;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
package com.pudding;

import bean.Student;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

/*
java.io.NotSerializableException
Student对象不支持序列化
*/
public class ObjectOutputStreamTest01 {
public static void main(String[] args) throws Exception {
//创建Java对象
Student s = new Student(1111,"zhangsan");
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
//序列化对象
oos.writeObject(s);
//刷新
oos.flush();
//关闭
oos.close();
}
}
package com.pudding;

import java.io.FileInputStream;
import java.io.ObjectInputStream;

/*
反序列化
*/
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
//开始反序列化,读
Object obj = ois.readObject();
//反序列化回来是异构学生对象,所以会调用学生对象的toString方法
System.out.println(obj);//Student{no=1111, name='zhangsan'}
ois.close();
}
}

序列化多个对象

注:一次可以序列化多个对象,将多个对象放到集合当中,序列化集合

  • 参与序列化的ArrayList集合以及集合中的元素User都需要实现java.io.Serializable接口
package bean;

import java.io.Serializable;

public class User implements Serializable {
private int no;
private String name;

public User() {
}

public User(int no, String name) {
this.no = no;
this.name = name;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}

序列化集合

package com.pudding;

import bean.User;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class ObjectOutputStreamTest02 {
public static void main(String[] args) throws Exception {
List<User> userList = new ArrayList<>();
userList.add(new User(1,"zhangsan"));
userList.add(new User(2,"lisi"));
userList.add(new User(3,"wangwu"));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));

//一次序列化一个集合,这个集合对象中放了很多其他的对象
oos.writeObject(userList);

oos.flush();
oos.close();
}
}

反序列化集合

package com.pudding;

import bean.User;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;
import java.util.List;

/*
反序列化集合
*/
public class ObjectInputStreamTest02 {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("users"));
//Object obj = ois.readObject();
//System.out.println(obj instanceof List); //true
List<User> userList = (List<User>) ois.readObject();
for (User user : userList){
System.out.println(user);
}
ois.close();
}
}

2. transient关键字

package bean;

import java.io.Serializable;

public class User implements Serializable {
private int no;
//transient关键字,表示游离的,不参见序列化操作
private transient String name;

public User() {
}

public User(int no, String name) {
this.no = no;
this.name = name;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}

3. 关于序列化版本号

  • 第一:首先通过类名进行比对,如果类名不一样,肯定不是一个类
  • 第二:如果类名一样,再通过序列化版本号进行区分
  • 不同人编写同一个类,但这两个类确实不是同一个类,这个时候序列化版本就起上作用了,对于java虚拟机来说是可以区分的,因为这两个类都实现了Serializable接口,都有默认的序列化版本号,他们的序列化版本号不一样,所以区分开了(好处)
小球:com.pudding.java.bean.Student implement Serializable
小强:com.pudding.java.bean.Student implement Serializable
  • 不足:自动生成的序列化版本号缺点:一旦代码确定之后,不能进行后续的修改,因为只要修改,必然重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这个是一个全新的类
  • 最终结论:凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号,这样,以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类
package bean;

import sun.dc.pr.PRError;

import java.io.Serializable;

public class Student implements Serializable {

//如果没有手动写出序列化版本号,Java虚拟机看到Serializable接口会自动生成一个序列化版本号
//建议将序列化手动写出来,不建议自动生成
private static final long serialVersionUID = 1L;

private int no;
private String name;
private String email;

//过来很久,Student这个类源代码改动了
//源代码改动之后,需要重新编译,编译之后生成全新的字节码文件
//并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变
private int age;

public Student() {
}

public Student(int no, String name) {
this.no = no;
this.name = name;
}

public int getNo() {
return no;
}

public void setNo(int no) {
this.no = no;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}

六. java.io.File类

File类和四大家族没有关系,所
以File类不能完成文件的读和写
File对象代表什么?

  • 文件和目录路径名的抽象表示形式
  • C:\Driver 这是一个File对象
  • C:\Driver\Readme.txt 也是一个File对象
  • 一个File对象有可能对应的是目录,也可能是文件
  • File只是一个路径名的抽象表示形式

1. File类的常用方法

package com.pudding;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileTest02 {
public static void main(String[] args) {

File f1 = new File("D:\\学习.ppt");
//获取文件名
System.out.println("文件名:"+f1.getName());

//判断是否是一个目录
System.out.println(f1.isDirectory()); //false

//判断是否是一个文件
System.out.println(f1.isFile()); //true

//获取最后一次修改时间
long haomiao = f1.lastModified();//这个毫秒是从1970年到现在的总毫秒数
//将总毫秒数转换成日期
Date time = new Date(haomiao);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);

//获取文件大小
System.out.println(f1.length()); //获取文件大小
}
}
package com.pudding;

import java.io.File;

public class FileTest03 {
public static void main(String[] args) {
//File[] listFiles();
//获取当前目录下所有的子文件
File f = new File("D:\\IDEA");
File[] files = f.listFiles();
//foreach
for (File file : files) {
System.out.println(file.getAbsoluteFile());
}
}
}

2. 拷贝目录

package com.pudding;

import java.io.*;

public class CopyAll {
public static void main(String[] args) {
//拷贝源
File srcFile = new File("D:\\IDEA\\code\\JDBC");
//拷贝目标
File destFile = new File("E:\\");
//调用方法拷贝
copyDir(srcFile,destFile);
}

/**
* 拷贝目录
* @param srcFile 拷贝源
* @param destFile 拷贝目标
*/
private static void copyDir(File srcFile,File destFile){
if (srcFile.isFile()) {
//srcFile如果是一个文件的话,递归结束
//是文件需要拷贝,一边读,一边写
FileInputStream in = null;
FileOutputStream out = null;
try {
//读这个文件
in = new FileInputStream(srcFile);
//写到这个文件中
String path = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\") + srcFile.getAbsolutePath().substring(3);
out = new FileOutputStream(path);
//一边读,一边写
byte[] bytes = new byte[1024*1024]; //一次复制1MB
int readCount = 0;
while ((readCount = in.read()) != -1){
out.write(bytes,0,readCount);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

return;
}
//获取源下面的子目录
File[] files = srcFile.listFiles();
for (File file:files){
//获取所有文件的(包括目录和文件)绝对路径
//System.out.println(file.getAbsoluteFile());
if (file.isDirectory()) {
//新建相应的目录
String srcDir = file.getAbsolutePath();
String destDir = (destFile.getAbsolutePath().endsWith("\\") ? destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\") + srcDir.substring(3);
File newFile = new File(destDir);
if (!newFile.exists()) {
newFile.mkdirs();
}
}
//递归调用
copyDir(file,destFile);
}
}
}

七. IO和Properties联合使用

  • IO流:文件的读和写
  • Properties:是一个Map集合,key和value都是String类型

非常好的设计理念:

  • 以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取
  • 将来只需要修改这个文件内容,java代表不需要改动
  • 编译,服务器也不需要重启,就可以拿到动态信息

类似以上机制的这种文件被称为配置文件,并且配置文件中内容格式是:

  • key1=value
  • key2=value
  • 的时候,我们把这种配置文件叫做属性配置文件

java规范中要求,属性配置文件建议以.properties结尾,但这不是必须的

  • 其中properties是专门存放属性配置文件内容的一个类

Java——I/O流_System_04

package com.pudding;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Properties;

public class IoPropertiesTest {
public static void main(String[] args) throws Exception {
/*
Properties是一个Map集合,key和value都是String类型
想将userinfo文件中的数据加载到Properties对象当中
*/
//新建一个输入流对象
FileReader reader = new FileReader("IO流/userinfo.properties");

//新建一个map集合
Properties pro = new Properties();

//调用Properties对象的load方法将文件中的数据加载到Map集合中
pro.load(reader); //文件中的数据顺着管道加载到Map集合当中,其中等号=左边做key,右边为value

//通过key来获取value
String username = pro.getProperty("username");
System.out.println(username);

String password = pro.getProperty("password");
System.out.println(password);
}
}


标签:java,new,io,import,Java,public,out
From: https://blog.51cto.com/u_15923298/5971068

相关文章

  • Java——多线程
    文章目录​​一.多线程概述​​​​1.什么是进程?什么是线程?​​​​2.进程和线程的关系​​​​3.多线程并发​​​​4.分析以下程序有几个线程​​​​5.Java实现线......
  • java中Integer的细节【面试】
    本文主要讲述Integer包装类的细节,通过创建Integer类的方式不同,探讨区别示例代码如下:1publicclassIntegerExercise{2publicstaticvoidmain(String[]args......
  • java中的String类与Integer包装类的转换
    本文主要讲述java中的String类与Integer类的相互转化示例代码如下:1publicclassWrapperInteger{2publicstaticvoidmain(String[]args){3Int......
  • java 编程式事务、声明式事务
    在Spring体系中,关于事务的管理有两种模式,分别是编程式事务和声明式事务1.什么是编程式事务编程式事务是指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较......
  • Java Web基础概述
    文章目录​​一.JavaWeb基本概念​​​​1.前言​​​​2.web应用程序​​​​3.静态web​​​​4.动态web​​​​二.Web结构​​​​1.什么是后端开发​​​​2.......
  • Java Web开发环境配置
    一.安装Tomcattomcat提供了两种使用方式:安装版本和免安装版本(解压即可使用)1.下载​​Tomcat官方网站进行下载​​tar.gz是linux下的安装包2.解压解压完成就可以直接使用......
  • Java编程思想21
    2.使用显示的Lock对象  JavaSE5的java.util.concurrent类库还包含有定义在java.util.concurrent.locks中的显式的互斥机制。Lock对象必须被显式地创建、锁定和释放。因......
  • Java 批量大文件上传下载
    ​ 文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可以直接把文件转化为字节流上传到服务器,但在文件比较大的情况下,用普通的方式进行上传,这可不是一个好的办法......
  • fastjson提取json返回值(java)
    返回json数据:{"data":{"offset":2,"total":2952,"restTotal":2950,"dataList":[{"ISBN":"9787539197456",......
  • JavaScript 中0.1+0.2 不等于 0.3 的问题
    在JavaScript中,有时候你可能会发现0.1+0.2不等于0.3。这是因为JavaScript使用的是浮点数来表示小数,而浮点数在计算机内部是用二进制表示的,这导致了一些精度问题。......