java进阶-第十二讲 IO流
1 File类
在java中File类代表了什么意思?
file:文件
java中File类的描述:
An abstract representation of file and directory pathnames.
File代表了文件和目录,不仅仅只是文件,一定要清楚
2 File的构造方法
File ( File parent, String child)
Creates a new File instance from a parent abstract pathname and a child pathname string.
File ( String pathname)
Creates a new File instance by converting the given pathname string into an abstract pathname.
File ( String parent, String child)
Creates a new File instance from a parent pathname string and a child pathname string.
File ( URI uri)
Creates a new File instance by converting the given file: URI into an abstract pathname.
3 成员方法
boolean createNewFile() // 创建一个文件
Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist.
String getParent() // (文件与目录)的上一级目录
Returns the pathname string of this abstract pathname's parent, or null if this pathname does not name a parent directory.
boolean isDirectory() //判断当前的File对象是否是一个目录
Tests whether the file denoted by this abstract pathname is a directory.
boolean isFile() // 判断当前的File对象是否是一个文件
Tests whether the file denoted by this abstract pathname is a normal file.
boolean mkdir() // 创建一个目录
Creates the directory named by this abstract pathname.
boolean mkdirs() // 创建多级目录
Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories.
String getAbsolutePath()
Returns the absolute pathname string of this abstract pathname.
File[] listFiles() // 返回一个File[]数组,
Returns an array of abstract pathnames denoting the files in the directory denoted by this abstract pathname.
4 应用
package com. tj. IO. fileTest;
import java. io. File;
import java. io. FileNotFoundException;
public class FileTest02 {
public static void main ( String[ ] args) {
File file = new File ( "F:\\IdeaProjects\\Study\\src\\com\\tj\\demo01" ) ;
try {
scanPakage ( file) ;
} catch ( FileNotFoundException e) {
e. printStackTrace ( ) ;
}
}
private static void scanPakage ( File file) throws FileNotFoundException {
if ( file == null) {
throw new FileNotFoundException ( "文件不存在!" ) ;
}
if ( file. isFile ( ) ) {
System. out. println ( file. getAbsolutePath ( ) ) ;
return ;
}
File[ ] files = file. listFiles ( ) ;
for ( File childFile : files) {
if ( childFile. isDirectory ( ) ) {
scanPakage ( childFile) ;
} else {
System. out. println ( childFile. getAbsolutePath ( ) ) ;
}
}
}
}
4.1 进一步的应用
需求:复制一个包从F:\\IdeaProjects\\Study\\src\\com\\tj 复制到
E:\\IdeaProjects\\Study\\src\\com\\tj
怎么做?
思路:
1. 要用到哪些知识?递归 + IO + isfile,isdirectory,mkdirs
2. 如果是文件,就要用到IO进行文件的拷贝
3. 如果是目录,就要新建目录
复习:
文件的拷贝
1. 确定源(从哪个文件拷贝,拷贝到哪里去)
2. 打开流(要使用到哪个流?Input Output)(字符流和字节流)
3. 操作
4. 关闭流
当成作业,拷贝一个文件夹。
package com. tj. IO. fileTest;
import java. io. *;
public class CpyDir {
public static void main ( String[ ] args) {
File srcFile = new File ( "F:/IdeaProjects/Study/src/com/tj" ) ;
File destFile = new File ( "E:/" ) ;
try {
cpyDir ( srcFile, destFile) ;
} catch ( FileNotFoundException e) {
e. printStackTrace ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
public static void cpyDir ( File srcFile, File destFile) throws IOException {
checkNull ( srcFile) ;
if ( srcFile. isFile ( ) ) {
copyFile ( srcFile, destFile) ;
return ;
}
File[ ] files = srcFile. listFiles ( ) ;
for ( File file : files) {
if ( file. isDirectory ( ) ) {
createNewDir ( destFile, file) ;
}
cpyDir ( file, destFile) ;
}
}
private static void createNewDir ( File destFile, File file) {
String srcPath = file. getAbsolutePath ( ) ;
String destPath = destFile. getAbsolutePath ( ) ;
String newPath = ( destPath + srcPath. substring ( 3 ) ) ;
File newFile = new File ( newPath) ;
if ( ! newFile. exists ( ) ) {
newFile. mkdirs ( ) ;
}
}
private static void copyFile ( File srcFile, File destFile) throws IOException {
InputStream fis = null;
OutputStream fos = null;
String srcPath = srcFile. getAbsolutePath ( ) ;
String destPath = destFile. getAbsolutePath ( ) ;
String newPath = ( destPath + srcPath. substring ( 3 ) ) ;
destFile = new File ( newPath) ;
try {
fis = new FileInputStream ( srcFile) ;
fos = new FileOutputStream ( destFile) ;
byte [ ] flush = new byte [ 1024 * 1024 ] ;
while ( fis. read ( flush) != - 1 ) {
fos. write ( flush) ;
fos. flush ( ) ;
}
} finally {
if ( fos != null) {
fos. close ( ) ;
}
if ( fis != null) {
fis. close ( ) ;
}
}
}
private static void checkNull ( File srcFile) throws FileNotFoundException {
if ( srcFile == null) {
throw new FileNotFoundException ( "文件找不到!" ) ;
}
}
}
5 关于包装流
FileInputStream:
如果我们按照Byte的大小去读,效率比较低。
read() : 1个Byte 1个Byte的读
应用中,我们都需要开辟一个缓冲区,也就是字节数组byte[] flush
read(flush):往字节数组flush中读入数据,读满之后,一次性写出。
这个缓存数组是我们可以自己控制大小的
这样的话效率会好很多。
BufferedInputStream:已经有缓存的字节输入流
Buffered:已缓存的
猜:也就是说这个BufferedInputStream中,自带一个缓存字节数组。
1. 自带byte buf[ ]
2. 构造
public BufferedInputStream ( InputStream in) {
this ( in, DEFAULT_BUFFER_SIZE) ;
}
参数:InputStream in :抽象类;传递实参的时候,一定要传一个InputStream的子类,多态
这里,我们可以传入一个FileInputStream fis
this ( in, DEFAULT_BUFFER_SIZE) ; 调用一个有两个参数的构造方法
默认的缓冲区大小为8192
3. 成员方法:
read ( )
close ( )
这个read方法调用的时候,还需要再开byte 数组吗?不用了。
这个close ( ) 方法被调用的时候,还需要关闭FileInputStream吗?不需要
4. BufferedInputStream叫做包装流,它把InputStream包装了一下,包装成带有缓冲区的
字节输入流。在这个包装流中,InputStream的子类,都叫做结点流。装饰模式。
package com. tj. IO;
import java. io. *;
public class IOTest03 {
public static void main ( String[ ] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream ( new FileInputStream ( "F:\\IdeaProjects\\Study\\src\\com\\tj\\IO\\小人书" ) ) ;
bos = new BufferedOutputStream ( new FileOutputStream ( "F:\\IdeaProjects\\Study\\src\\com\\tj\\IO\\小人书02" ) ) ;
int len = 0 ;
while ( ( len = bis. read ( ) ) != - 1 ) {
bos. write ( len) ;
bos. flush ( ) ;
}
} catch ( FileNotFoundException e) {
e. printStackTrace ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( bos != null) {
try {
bos. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
if ( bis != null) {
try {
bis. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
6 ObjectInput/OutputStream
应用最广泛的,也是最重要的一个流:对象输入输出流
ObjectInput/OutputStream:这个流的核心要输入输出的东西:对象
java中最重要的是:对象
作用:序列化与反序列化
什么是序列化:
将内存中的对象写到文件中
什么是反序列化:
将对象从文件中读入到内存中
对象创建了之后在哪里存放:堆内存空间
内存:一旦断电了之后,内存是不是就要释放。程序运行结束之后,内存也要释放。
内存释放之后,对象还存在吗?不存在了。
有的对象我们希望不要反复的创建。把对象存入到硬盘上。每次要用的时候加载一下。
对象到底是什么东西?是不是一个二进制序列。一串二进制数据。数据是不是可以放到硬盘上。
User usr = new User(...);
将内存中的对象放入到硬盘文件的过程叫做序列化(OutputStream)
将硬盘文件中的对象写入到内存中的过程叫做反序列化(InputStream)
序列化与反序列有一个专用的流:ObjectInput/OutputStream
7 序列化与反序列化
定义:
将内存中的对象写入到硬盘文件中---序列化
将硬盘文件中的对象数据读入到内存中---反序列化
前提:
1. 要有对象
2. 类一定要实现Serializable接口,
只有实现了Serializable接口的类所产生的对象才能被序列化与反序列化
3. ObjectOutputStream:序列化 ObjectInputStream:反序列化
刨根问底:
Serializable接口到底是个啥?
如果一个类不实现该接口,在序列化的时候,会报:NotSerializableException
所以说,对于可以被序列化与反序列化的对象而言,它所属的类一定要实现Serializable
接口。为什么非得实现?
应用场景:
我序列化好了一个user对象,过了一段时间,项目的需求发生一些改变,需要给Uer类增加一个属性。
于是乎,我改了代码。
但是,其他同事想要反序列化原来的user对象。这时候,会出现以下错误:
java.io.InvalidClassException: com.tj.IO.serializeTest.User;
local class incompatible:
stream classdesc serialVersionUID = -3484567756084152433,
local class serialVersionUID = 1411792367602759118
序列化版本号不一致。
非法类异常
推断:这个版本号是谁给的?JVM给我们的,JVM凭什么给我们定义的类一个版本号?
因为我们的User类实现了Serializable接口
这个接口为什么没有内容呢?因为它是一个标识接口,这个接口对于我们程序员来说
没有太大的使用意义,它是给JVM看的。JVM看到类实现了改接口,就会给它分配一个
序列化版本号(serialVersionUID),这个版本号就是用来:序列化好的对象可以通过
该版本号找到它所对应的类。如果,序列化好的对象中的版本号,与类所拥有的版本号
不一致,那么无法反序列化,因为JVM认为这不是同一个类的。
这是JVM分配的,那么它是存在缺陷的。怎么办呢?
一般情况下,现实开发中,我们都需要自定义序列化版本号。自定义的序列化版本号
要求全球唯一。
如果改变了类的属性之后,反序列化所得结果有值的部分仍是以前的序列化好的,
新加入的属性值会给一个默认值。
开发过程中,要和团队的人商议好,这个序列化版本号不能冲突。
serialVersionUID是一个常量,一旦定义不要修改。
readObject()这个方法只会按照当前的类结构来读。也就是说:
以前序列化的对象,放在硬盘文件中。现在,已经改变了代码。
反序列化的时候,通过序列化版本号,来找到当前的类,按照当前的类结构来反序列化
少的就舍弃,多的就补上默认值。
package com. tj. IO. serializeTest;
import java. io. Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1 L;
private int id;
public User ( ) {
}
public User ( int id) {
this . id = id;
}
public static long getSerialVersionUID ( ) {
return serialVersionUID;
}
public int getId ( ) {
return id;
}
public void setId ( int id) {
this . id = id;
}
@Override
public String toString ( ) {
return "User{" +
"id=" + id +
'}' ;
}
}
package com. tj. IO. serializeTest;
import java. io. FileOutputStream;
import java. io. IOException;
import java. io. ObjectOutputStream;
import java. util. ArrayList;
import java. util. HashMap;
import java. util. List;
public class SerializeTest {
public static void main ( String[ ] args) {
User zangs = new User ( 1 ) ;
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream ( new FileOutputStream ( "user2" ) ) ;
oos. writeObject ( zangs) ;
oos. flush ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( oos != null) {
try {
oos. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
package com. tj. IO. serializeTest;
import java. io. FileInputStream;
import java. io. IOException;
import java. io. ObjectInputStream;
public class DeSerializeTest {
public static void main ( String[ ] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream ( new FileInputStream ( "F:\\IdeaProjects\\Study\\user2" ) ) ;
Object object = ois. readObject ( ) ;
System. out. println ( object) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} catch ( ClassNotFoundException e) {
e. printStackTrace ( ) ;
} finally {
if ( ois != null) {
try {
ois. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
8 接口的补充
package com. tj. IO. lambdaTest;
@FunctionalInterface
public interface IUser {
void test ( ) ;
default void t1 ( ) {
System. out. println ( "hello world" ) ;
}
default void t3 ( ) {
System. out. println ( "hello jsu" ) ;
}
static void t2 ( ) {
System. out. println ( "static func" ) ;
}
static void t4 ( ) {
System. out. println ( "hello csj" ) ;
}
}
package com. tj. IO. lambdaTest;
import java. util. ArrayList;
import java. util. List;
public class LTest {
public static void main ( String[ ] args) {
IUser user = new IUser ( ) {
@Override
public void test ( ) {
System. out. println ( "12345" ) ;
}
} ;
user. test ( ) ;
IUser iUser = ( ) - > System. out. println ( "hi!" ) ;
iUser. test ( ) ;
iUser. t1 ( ) ;
IUser. t2 ( ) ;
iUser. t3 ( ) ;
IUser. t4 ( ) ;
List< Integer> list = new ArrayList < > ( ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. add ( 1 ) ;
list. forEach ( System. out: : println) ;
}
}