最近在准备面试,所以把之前的笔记都看了一遍,这是在学习IO流时做的笔记,觉得还是挺详细的,和大家分享一下。准备面试时间比较赶,我平时的笔记是在腾讯文档上中的,直接拷贝过来了,可能排版不太兼容,大家见谅,有时间我再好好整理排版。
目录
int available()方法:返回流当中剩余的没有读到的字节数量
拷贝1:FileInputStream、FileOutputStream
InputStreamReader:转换流,字节流转换为字符流
getParent()和getParentFile()方法:
-
IO流图示
-
什么是IO?
-
I:Input
-
O:Output
-
通过IO可以完成硬盘文件的读和写
-
-
IO流的分类
-
按流的方向分类(以内存为参照物):
-
输入流:进入到内存,叫作“输入”(Input),或者叫作“读”
-
输出流:从内存中出来,叫作“输出”(Output),或者叫作“写”
-
-
按照读取数据方式不同分类:
-
字节流:按照字节的方式读取数据,一次读取1个字节(byte),等同于一次读取8个二进制位。字节流是万能的,什么类型的文件都可以读取,包括:文本文件、图片、音频、视频等
-
字符流:按照字符的方式读取数据,一次读取一个字符。这种流是为了方便读取普通文本文件而存在的,字符流不能读取图片、声频、视频,只能读取纯文本文件(word是富文本,不能读取)
-
-
-
Java中的IO流
-
Java已经把IO流都写好了,Java中所有的流都在“java.io.*”下
-
我们只要研究如何new流对象,调用流对象的哪个方法进行读和写
-
-
IO流四大家族
-
四大家族:
-
java.io.InputStream 字节输入流
-
java.io.OutputStream 字节输出流
-
java.io.Reader 字符输入流
-
java.io.Writer 字符输出流
-
-
技巧:在Java中,只要“类名”以“Stream”结尾的都是字节流;以“Reader/Writer”结尾的都是字符流
-
close()关闭流:
-
所有流都实现了“java.io.Closeable”接口,都可以用close()方法关闭。
-
流是一个内存和硬盘之间的管道,会占用很多资源,流使用完一定要关闭
-
-
flush()刷新:
-
所有输出流都实现了“java.io.Flushable”接口,都可以用flush()刷新。输出流在最终输出之后,一定要调用flush()刷新一下。
-
刷新就是把管道中剩余为输出的数据强行全部输出(清空管道)。刷新的作用就是清空管道
-
如果不刷新,有可能会造成数据丢失
-
-
-
java.io下的16个流
-
重点掌握FileInputerStream、FileOutputStream,其他原理类似;ObjectInputStream、ObjectOutputStream也比较常用
-
16个流
-
文本专属:
-
java.io.FileInputerStream 文件的字节输入流(重点)
-
java.io.FileOutputStream 文件的字节输出流(重点)
-
java.io.FileReader 文件的字符输入流
-
java.io.FileWriter 文件的字符输出流
-
-
转换流(将字节流转换为字符流)
-
java.io.InputStreamReader 转换输入流
-
java.io.OutputStreamWriter 转换输出流
-
-
缓冲流专属
-
java.io.BufferReader 带缓冲的字符输入流
-
java.io.BufferWriter 带缓冲的字符输出流
-
java.io.BufferInputStream 带缓冲的字节输入流
-
java.io.BufferOutputStream 带缓冲的字节输出流
-
-
数据流专属
-
java.io.DataInputStream 数据输入流
-
java.io.DataOutputStream 数据输出流
-
-
标准输出流
-
java.io.PrintWriter 字符输出流
-
java.io.PrintStream 标准输出流(重点)
-
-
对象专属流
-
java.io.ObjectInputStream 对象输入流(重点)
-
java.io.ObjectOutputStream 对象输出流(重点)
-
-
-
-
文件的路径
-
IDEA中,默认的当前路径是工程文件Project的根目录
-
-
read()方法:读
-
read()
-
无参数时,每次只会读取一个字节,效率较低
-
调用一次读取一个字节,每次调用都会自动向下读取
-
read方法的返回值是读取到的“字节”的阿斯克码值;如果没有读取到字节就会返回-1
-
使用示范:
-
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
int readData = fis.read();
-
read(byte数组)
-
参数是byte数组,每次会读取byte数组.length个字节,效率较高
-
返回值是本次读取到的字节数量;如果没有读取到字节会返回-1
-
读取到的字节的阿斯克码值会保存在byte数组中,从位置0开始向后覆盖;如果最后读取到的字节数小与于数组长度,则新字节无法把所有的旧字节覆盖,应该舍弃最后多出的字节
-
使用示范:
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
byte[] bytes = new byte[4];// 数组长度是4,则每次最多读取4个字节
int readData = fis.read(bytes);
-
String()方法:转换为字符串
-
String(byte数组)
-
参数是byte数组时,会把整个byte数组转换为字符串
-
返回值是字符串
-
使用示范:
-
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
byte[] bytes = new byte[4];
int readData = 0;
while ((readData = fis.read(bytes)) != -1){
// String(byte数组)方法可以把byte数组全部转换为字符串。不合理,应该是读取了多少字符就转多少字符
System.out.println(new String(bytes));
}
-
string(byte数组,起始位置,读取的个数)
-
参数是如上时,会把byte数组的部分内容转换为字符串,以“起始位置”和“读取的个数”来确定需转换的部分
-
使用示范:
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
byte[] bytes = new byte[4];
int readData = 0;
while ((readData = fis.read(bytes)) != -1){
// String(byte数组)方法可以把byte数组全部转换为字符串。不合理,应该是读取了多少字符就转多少字符
System.out.println(new String(bytes, 0, readData));
}
-
FileInputStream(字节输入流)读取txt文件
-
FileInputStream是字节输入流
-
读取txt文件中的内容并输出到控制台
-
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
// java.io.FileInputStream:
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建文件字节输入流对象
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
byte[] bytes = new byte[4];
int readCount = 0;
// read(bytes)每次读取bytes.length个字符,读取到的字符保存在数组中
while ((readCount = fis.read(bytes)) != -1){
// string(byte数组,起始位置,读取的个数):把byte数组中的字节转换为字符串
System.out.print(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();
}
}
}
}
}
-
int available()方法:返回流当中剩余的没有读到的字节数量
-
作用:返回流当中剩余的没有读到的字节数量
-
通过available方法获取总字节数,创建一个相应长度的byte数组,一次读取全部字节。因为byte数组长度不能太大,所以不能用来读取大文件(不多于574560字节)
-
代码展示:
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
System.out.println("字节总数量:" + fis.available());
// 读取一个字节
int readByte = fis.read();
System.out.println("剩下的字节数量=" + fis.available());
// 通过available方法获取总字节数,创建一个相应长度的byte数组,一次读取全部字节
byte[] bytes = new byte[fis.available()];
int readCount = fis.read(bytes);// 不用循环,一次读取全部
System.out.println(new String(bytes));
-
long skip(long n):跳过n个字节不读
-
作用:跳过n个字节不读
-
代码展示
-
fis = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
System.out.println("字节总数量:" + fis.available());
// 使用skip方法跳过n个字节
fis.skip(3);
System.out.println("跳过3个字节后剩余的字节数=" + fis.available());
-
write()方法:写
-
作用:往文件里面写入数据
-
write(byte[])构造方法:
-
把byte数组里的全部数据写出
-
-
b. write(byte[],起始位置, 数量)构造方法:
-
把byte数组的部分数据写出
-
getBytes()方法:转换为byte数组
-
作用:可以把字符串转换为byte数组
-
代码示范:
-
String s = "\n今晚月色真美";
// 将字符串转换为byte数组
byte[] bytes = s.getBytes();
-
FileOutputStream(字节输出流)写出到txt
-
FileOutputStream是字节输出流
-
创建字节输出流对象时,文件不存在时会自动新建
-
FileOutputStream(文件目录)构造方法:
-
这个构造方法会把原来文件的内容清空(从文件开头写入),谨慎使用
-
-
b. FileOutputStream(文件目录,true/false)构造方法:
-
这个构造方法可以通过第二个参数设置从开头还是末尾进行追加
-
true是从末尾追加,false从开头写出(相当于和没有第二个参数的构造方法一样)
-
代码展示:将byte数组数据写出到txt文件
fos = new FileOutputStream("E:\\IOliu_ceshi\\temp.txt", true);
// 准备要写出的数据:byte数组
byte[] bytes = {97, 98, 99, 102, 105, 122};
// 写出数据。write(byte数组)方法把byte数组的全部数据写出
fos.write(bytes);
// write(byte数组,起始位置,个数):写出byte数组的部分数据
fos.write(bytes, 2, 1);
// 写完之后,一定要刷新
fos.flush();
-
代码展示:将字符串数据写出到txt文件
-
将字符串转换为byte数组在写出
-
fos = new FileOutputStream("E:\\IOliu_ceshi\\temp.txt", true);
// 准备要写入的数据:字符串
String s = "\n今晚月色真美";
// 将字符串转换为byte数组
byte[] bytes = s.getBytes();
// 写出数据
fos.write(bytes);
// 写完之后,一定要刷新
fos.flush();
-
拷贝1:FileInputStream、FileOutputStream
-
流程:
-
文件原地址 ----读----> 内存 ----写---->新地址
-
一边读一边写
-
-
代码展示
-
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 使用FileInputStream和FileOutputStream完成文件的拷贝
* 一边读一边写。使用的是字节流,所以可以拷贝任意类型的文件
*/
public class Copy01 {
public static void main(String[] args) {
FileInputStream fis = null;// 字节输入流对象
FileOutputStream fos = null;// 字节输出流对象
try {
// 字节输入流对象
fis = new FileInputStream("C:\\Users\\young\\Desktop\\Mojito-周杰伦 .mp3");
// 字节输出流对象
fos = new FileOutputStream("E:\\IOliu_ceshi\\Mojito-周杰伦 .mp3");
System.out.println("大小:" + fis.available());
// 一边读一边写
byte[] bytes = new byte[1024 * 1024];// 一次拷贝1M
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,避免前面的流出异常影响后面的流关闭
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-
FileReader:字符输入流
-
FileReader是字符输入流,只能读取普通文本。读取文本内容时,比较方便快捷
-
代码展示:
-
public static void main(String[] args) {
FileReader reader = null;
try {
// 创建文件字符输入流
reader = new FileReader("E:\\IOliu_ceshi\\temp.txt");
// 开始读
char[] chars = new char[4];// 一次读4个
int readCount = 0;
while ((readCount = reader.read(chars)) != -1) {
System.out.print(new String(chars, 0, readCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
-
FileWriter:字符输出流
-
文件字符输出流,只能输出普通文本
-
使用的是char[]数组
-
可以使用write(String字符串)直接写出字符串
-
代码展示:
-
public static void main(String[] args) {
FileWriter out = null;
try {
// 创建文件输出流对象
out = new FileWriter("E:\\IOliu_ceshi\\temp.txt");// 覆盖写入
// out = new FileWriter("E:\\IOliu_ceshi\\temp.txt", true);// 追加写入
// 创建需要写出的数据:char数组
char[] chars = {'今', '晚', '月', '色', '真', '美', '!'};
out.write(chars);// 写出char数组全部数据
out.write(chars, 4, 2);// 写出char数组部分数据
out.write("\n风也温柔!");// 直接写入字符串
// 刷新
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
-
拷贝2:FileReader、FileWriter
-
使用FileReader和FileWriter完成文件的拷贝
-
一边读一边写
-
使用的是字符流,只能拷贝普通文本文件
-
代码展示:
-
package com.bjpowernode.java.io;
import java.io.*;
public class Copy02 {
public static void main(String[] args) {
FileReader in = null;// 字节输入流对象
FileWriter out = null;// 字节输出流对象
try {
// 字符输入流对象
in = new FileReader("E:\\IOliu_ceshi\\temp.txt");
// 字符输出流对象
out = new FileWriter("E:\\IOliu_ceshi\\temp2.txt");
// 边读边写
char[] chars = new char[1024 * 1024];// 1M
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 {
// 关闭两个流时分开try,避免前面的流出异常影响后面的流关闭
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
-
BufferedReader:带有缓冲区的字符输入流
-
BufferedReader是带有缓冲区的字符输入流,使用的时候不需要自定义char数组或byte数组,自带缓存
-
当一个流的构造方法中需要一个流的时候,这个被传进去的流叫做“节点流”,外部负责包装的流叫做“包装流”,或者叫“处理流”
-
关闭流时只需要关闭最外层流(最外层包装流),节点流会自动关闭
-
readLine()方法:读一行
-
readLine()方法每调用一次读取一行(不包括换行符),读不到时返回null
-
-
代码展示:
-
package com.bjpowernode.java.io;
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("E:\\IOliu_ceshi\\temp.txt");
// 当前这个程序的节点流是FileReader,包装流/处理流是BufferedReader
BufferedReader br = new BufferedReader(reader);
// 读一行。readLine()方法每调用一次读取一行(不包括换行符),读不到时返回null
String firstLine = br.readLine();
System.out.println(firstLine);
String s = null;
while ((s = br.readLine()) != null) {
System.out.println(s);
}
// 关闭流。只需要关闭最外层流(最外层包装流),节点流会自动关闭
br.close();
}
}
-
InputStreamReader:转换流,字节流转换为字符流
-
InputStreamReader:转换流,字节流转换为字符流
-
代码展示:
-
package com.bjpowernode.java.io;
import java.io.*;
public class BUfferedReaderTest02 {
public static void main(String[] args) throws Exception {
// // 1、字节流对象
// FileInputStream in = new FileInputStream("E:\\IOliu_ceshi\\temp.txt");
//
// // 2、InputStreamReader方法将字节流转换为字符流。in是节点流,reader是包装流
// InputStreamReader reader = new InputStreamReader(in);
//
// // 3、这个构造方法只能传一个字符流,不能传字节流(所以通过InputStreamReader方法把字节流转换为了字符流)
// // reader是节点流,br是包装流
// BufferedReader br = new BufferedReader(reader);
// 合并123步
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("E:\\IOliu_ceshi\\temp.txt")));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
// 关闭最外层
br.close();
}
}
-
BufferedWriter:带有缓冲区的字符输出流
-
BufferedWriter是带有缓冲区的字符输出流
-
代码展示:
-
package com.bjpowernode.java.io;
import java.io.*;
public class BufferedWriterTest {
public static void main(String[] args) throws Exception {
// 创建带有缓冲区的字符输出流
// BufferedWriter out = new BufferedWriter(new FileWriter("E:\\IOliu_ceshi\\temp.txt"));
// BufferedWriter out = new BufferedWriter(new FileWriter("E:\\IOliu_ceshi\\temp.txt", true));
// 使用OutputStreamWriter转换流:字节流转换为字符流
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:\\IOliu_ceshi\\temp.txt", true)));
out.write("今晚月色真美");
out.write("\n");
out.write("风也温柔\n");
out.flush();
out.close();
}
}
-
DataOutputStream:数据专属的字节输出流
-
DataOutputStream是数据专属的字节输出流
-
这个流可以将数据连同数据的类型一并写入文件
-
注意:所写入的文件不是普通文本文件,无法使用记事本正常打开,会乱码
-
代码展示:
-
package com.bjpowernode.java.io;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class DataOutputStreamTest {
public static void main(String[] args) throws Exception {
// 创建数据专属的字节输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\IOliu_ceshi\\temp3.txt"));
// 准备要写的数据
byte b = 1;
short s = 2;
int i = 3;
long l = 4L;
float f = 3.0F;
double d = 3.14;
boolean sex = true;
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();
}
}
-
DataInputStream:数据字节输入流
-
DataOutputStream写的文件只能使用DataInputStream去读
-
读的时候需要提前知道写入的顺序,读的顺序需要和写的顺序一致,才可以正常取出数据
-
代码展示(读DataOutputStream写入的文件,也就是上面的那段代码):
-
package com.bjpowernode.java.io;
import java.io.DataInputStream;
import java.io.FileInputStream;
public class DataInputStreamTest01 {
public static void main(String[] args) throws Exception {
DataInputStream dis = new DataInputStream(new FileInputStream("E:\\IOliu_ceshi\\temp3.txt"));
// 开始读,顺序要符合文件数据的顺序
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();
}
}
-
PrintStream:标准输出流
-
java.io.PrintStream是标准的子节输出流,默认输出到控制台,标准输出流不需要手动关闭
-
可以改变标准输出流的输出方向
-
// 1、标准流指向log.txt文件(定义流的方向)
PrintStream printStream = new PrintStream(new FileOutputStream("E:\\IOliu_ceshi\\log.txt"));
// 2、修改输出方向,将输出方向指向log文件(使用流的方向)
System.setOut(printStream);
-
代码展示:
package com.bjpowernode.java.io;
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("hello world!");
// 改变标准输出流的输出方向(默认方向是控制台)
// 1、标准流指向log.txt文件(定义流的方向)
PrintStream printStream = new PrintStream(new FileOutputStream("E:\\IOliu_ceshi\\log.txt"));
// 2、修改输出方向,将输出方向指向log文件(使用流的方向)
System.setOut(printStream);
// 3、输出到log.txt文件
System.out.println("hello kitty");
}
}
-
日志工具:使用PrintStream标准输出流
-
日志工具代码:
-
package com.bjpowernode.java.io;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
// 日志工具
public class Logger {
/**
* 记录日志的方法
* @param msg 日志的内容
*/
public static void log(String msg) {
PrintStream printStream = null;
try {
// 1、标准流指向log.txt文件(定义流的方向)
printStream = new PrintStream(new FileOutputStream("E:\\IOliu_ceshi\\log.txt", true));
// 2、修改输出方向,将输出方向指向log文件(使用流的方向)
System.setOut(printStream);
// 获取当前时间
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.bjpowernode.java.io;
// 测试日志工具类
public class LogTest {
public static void main(String[] args) {
Logger.log("调用了System类的gc()方法,建议启动垃圾回收");
Logger.log("调用了UserService的doSome()方法");
Logger.log("用户尝试进行登录,验证失败");
}
}
-
File类
-
File类不属于四大家族,不能完成文件的读和写
-
File对象代表什么?
-
文件和目录路径名的抽象表达式
-
一个File对象有可能是目录,也有可能是文件
-
-
提示:掌握下面列出来的方法就可以了
-
File("目录")构造方法:
-
创建File对象
-
-
exists()方法:
-
判断某文件是否存在
-
-
createNewFile()方法:
-
以文件的形式创建
-
-
mkdir()方法:
-
以目录的形式创建
-
-
mkdirs()方法:
-
以多级目录的形式创建
-
-
getParent()和getParentFile()方法:
-
都是获取文件的上层目录,如果没有指定的父目录,则返回空
-
getParent() 的返回值是String型的,getParentFile()的返回值是File型的
-
-
以上方法的代码展示:
-
package com.bjpowernode.java.io;
import java.io.File;
import java.io.IOException;
public class FileTest01 {
public static void main(String[] args) throws IOException {
// 创建一个File对象
File f1 = new File("E:\\IOliu_ceshi\\File\\file1");
File f2 = new File("E:\\IOliu_ceshi\\File\\file2");
File f3 = new File("E:\\IOliu_ceshi\\File\\file3\\a\\b\\c");
// 判断f1是否存在
System.out.println(f1.exists());
// 如果f1不存在则以文件的形式创建
if (!f1.exists()) {
f1.createNewFile();
System.out.println("file1文件创建成功");
} else {
System.out.println("文件:file1存在");
}
// 如果f2不存在则以目录的形式创建
if (!f2.exists()) {
f2.mkdir();
System.out.println("file2目录创建成功");
} else {
System.out.println("目录:file2存在");
}
// 如果f3多级目录不存在则以目录的形式创建
if (!f3.exists()) {
f3.mkdirs();
System.out.println("file3多级目录创建成功");
} else {
System.out.println("多级目录:file3存在");
}
// 获取文件的路径
// getParent方法获取上层目录
String parentPath = f3.getParent();
System.out.println("f3的路径:" + parentPath);//E:\IOliu_ceshi\File\file3\a\b
File parentFile = f3.getParentFile();
System.out.println("获取f3的绝对路径:" + parentFile.getAbsolutePath());
}
}
-
getName()方法:
-
获取文件名
-
-
isDirectory()方法:
-
判断是否是目录
-
-
isFile()方法:
-
判断是否是文件
-
-
lastModified()方法:
-
获取文件最后一次修改时间,从1970年至今的毫秒数
-
-
length()方法:
-
获取文件的大小,单位是字节
-
-
listFiles()方法:
-
File[] listFiles()方法:获取当前目录下所有的子文件,调用对象需要是目录
-
-
以上方法的代码展示
package com.bjpowernode.java.io;
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("E:\\IOliu_ceshi\\temp.txt");
File f = new File("E:\\IOliu_ceshi");
// 获取文件名
System.out.println("文件名:" + f1.getName());
// 判断是否是目录
System.out.println(f1.isDirectory());// false
// 判断是否是文件
System.out.println(f1.isFile());// true
// 获取文件最后一次修改时间,从1970年至今的毫秒数
long haoMiao = f1.lastModified();
// 将毫秒数转换成日期
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());
// File[] listFiles()方法:获取当前目录下所有的子文件,调用对象需要是目录
File[] files = f.listFiles();
for (File file : files) {
System.out.println(file.getAbsolutePath());
}
}
}
-
目录的拷贝
-
直接看代码吧……
-
代码展示:
-
package com.bjpowernode.java.io;
import java.io.*;
/**
* 递归拷贝
* 难点:递归、文件路径的拼接
* 路径拼接思路:copy目标目录 + copy源文件名称
*/
public class CopyAll {
public static void main(String[] args) {
// 拷贝源(复制的文件)(从File的上级目录IOliu_ceshi开始,会把IOliu_ceshi拷贝到目标目录下)
File srcFile = new File("E:\\IOliu_ceshi\\File");
// 拷贝目标(粘贴的地方)("E:\\IOliu_ceshi\\File-拷贝"\\IOliu_ceshi\\……)
File destFile = new File("E:\\IOliu_ceshi\\File-拷贝");
// 调用拷贝的方法
copyDir(srcFile, destFile);
}
/**
* 拷贝
* 是文件则拷贝,是目录则创建
* @param srcFile 拷贝源(复制的文件)
* @param destFile 拷贝目标(粘贴的地方)
*/
private static void copyDir(File srcFile, File destFile) {
if (srcFile.isFile()) {
//如果是文件则拷贝,一边读一边写
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];
int readCount = 0;
while ((readCount = in.read(bytes)) != -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) {
//
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);
}
}
}
-
序列化和反序列化
-
图解
-
-
ObjectOutputStream类:序列化
-
实现Serializable接口
-
如果bena需要序列化,那么需要实现Serializable接口
-
通过源代码可以发现这个接口没有需要实现的方法,相当于是一个标识(标识供JVM参考)
-
不实现Serializable接口时,进行对象序列化时报NotSerializableException(对象不支持序列化)
-
JVM虚拟机看到实现Serializable接口后,会自动生产序列化版本号(不用手写,JVM会默认提供)
-
-
writeObject()方法:序列化对象
-
序列化单个对象代码展示:
-
创建bena
-
package com.bjpowernode.java.bean;
import java.io.Serializable;
// 如果bena需要序列化,那么需要实现Serializable接口
public class Student implements Serializable {
private int no;
private String name;
……
}
-
序列化
package com.bjpowernode.java.io;
import com.bjpowernode.java.bean.Student;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamTest01 {
public static void main(String[] args) throws Exception {
// 创建Student对象
Student s = new Student(1111, "zhangsan");
// 创建序列化对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\IOliu_ceshi\\xuliehua.txt"));
//序列化对象
oos.writeObject(s);
// 刷新
oos.flush();
// 关闭
oos.close();
}
}
-
ObjectInputStream类:反序列化
-
readObject()方法:反序列化
-
反序列化代码展示
package com.bjpowernode.java.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws Exception {
// 创建反序列化对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\IOliu_ceshi\\xuliehua.txt"));
// 开始反序列化,读
Object obj = ois.readObject();
// 反序列化回来是一个学生对象,会自动调用学生对象的toString方法
System.out.println(obj);
// 关闭流
ois.close();
}
}
-
序列化和反序列化多个对象
-
将对象封装到集合中,序列化和反序列化集合对象
-
代码展示:List集合
-
创建bena
-
-
package com.bjpowernode.java.bean;
import java.io.Serializable;
public class User implements Serializable {
private int no;
private String name;
}
-
序列化
package com.bjpowernode.java.io;
import com.bjpowernode.java.bean.User;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
// 将对象放到序列化集合中,可一次序列化多个对象,
// 参与序列化的ArrayList集合和集合中的元素User需要实现java.io.Serializable接口
public class ObjectOutputStreamTest02 {
public static void main(String[] args) throws Exception {
// 将需要序列化的多个数据存入集合
List<User> userList = new ArrayList<>();
userList.add(new User(1, "张三"));
userList.add(new User(2, "李四"));
userList.add(new User(3, "王五"));
userList.add(new User(4, "赵六"));
// 创建序列化对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\IOliu_ceshi\\xuliehua2.txt"));
// 序列化一个集合,集合中放了很多对象,相当于一次序列化多个对象
oos.writeObject(userList);
oos.flush();
oos.close();
}
}
-
反序列化
package com.bjpowernode.java.io;
import com.bjpowernode.java.bean.User;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
// 反序列化集合,相当于一次反序列化多个对象
public class ObjectInputStreamTest02 {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\IOliu_ceshi\\xuliehua2.txt"));
//Object obj = ois.readObject();
// System.out.println(obj instanceof List);
List<User> userList = (List<User>) ois.readObject();
for (User user : userList){
System.out.println(user);
}
ois.close();
}
}
-
transient关键字
-
ransient关键字:表示游离。如果bena的某个属性不参与序列化,可以通过该关键字来设置
-
代码展示
-
public class User implements Serializable {
private int no;
// transient关键字:表示游离,该属性不参与序列化
private transient String name;
}
-
序列化版本号
-
Java中区分类的机制:
-
通过类名区分,如果类名不一样,则肯定不是同一个类
-
如果类名一样,则通过序列化版本号进行区分
-
-
序列化版本号缺陷
-
这种自动生成序列化版本号的缺点是:一旦代码确定之后,不能进行后续的修改。因为一旦修改,必然会重新编译,此时会生成全新的序列化版本号,JVM就会认为这是一个全新的类
-
-
最终结论(解决方案):
-
凡是一个类实现了Serializable接口,建议给该类一个固定的序列化版本号。即使之后修改了代码,版本号不变,JVM会认为是同一个类
-
-
手动设置序列化版本号
-
手动设置序列化版本号,不采用自动生成
-
建议使用全球唯一的版本号,可用UUID
-
代码展示(这里为了简便,使用了简单的版本号)
-
-
public class Student implements Serializable {
// 设置序列化版本号
private static final long serialVersionUID = 1L;
private int no;
private String name;
}
-
IO和Properties联合使用
-
IO流:文件的读写
-
Properties(属性配置文件):是一个Map集合,key和value都是String类型,如果key重复则会自动覆盖
-
经常改变的数据可以写到Properties文件中,使用程序动态读取。将来只需要修改Properties文件中的内容即可,不需要改动Java代码,不需要重新编译,不需要重新启动服务器
-
类似的文件称之为配置文件,文件名一般采用“.Properties”结尾
-