IO流
概述:在程序中所有的数据都是以流的方式进行传输和保存的,程序通过输入流读取数据;当程序需要将一些数据长期保存起来的时候使用输出流完成。
流:用来完成程序和文件之间、程序和网络之间、程序和其他程序之间的数据传输。
File类的使用
- File类的一个对象,代表一个文件或一个文件目录;
- File类声明在java.io包下;
- File类中涉及的方法只是关于文件或文件目录的创建、删除、重命名、获取相关信息的方法,不涉及到写入或读取文件内容的操作。文件内容的操作,必须使用IO流来完成;
- File类的使用常将其实例化对象作为参数传递给流的构造器中。
1.File类的实例化
-
构造器一:public File(String pathname),pathname:文件的路径
-
构造器二:public File(String parent, String child)
-
构造器三:public File(File parent, String child)
@Test public void test1(){ //构造器一:public File(String pathname) var file1 = new File("Hello.txt");//相对于当前包下的文件 var file2 = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO/Hello.txt"); System.out.println(file1); System.out.println(file2); //构造器二:public File(String parent, String child) var file3 = new File("C:\\Users\\ASUS\\IdeaProjects","Ther"); System.out.println(file3); //构造器三:public File(File parent, String child) var file4 = new File(file3,"src\\JavaSE\\IO/Hello.txt"); System.out.println(file4); }
相对路径与绝对路径
相对路径:相对于某个路径下,指明的路径。
绝对路径:包含盘符在内的文件或文件目录的路径
分隔符
路径分隔符和系统有关,在windows和Dos系统下默认使用“\”来表示,在UNIX和URL中使用“/”来表示(实际上在windows下用/也不会报错),java程序支持跨平台运行,因此路径分隔符要慎用。为了解决在不同系统下分隔符不同的隐患,File类提供了一个常量:public static final String separator根据操作系统,动态的提供分隔符。
2.File类的常用方法
方法名 | 说明 |
---|---|
public String getAbsolutePath() | 获取绝对路径 |
public String getPath() | 获取相对路径 |
public String getName() | 获取文件名 |
File public File getParentFile() | 获取父级文件路径并返回FIle类型 |
public long length() | 获取文件内容长度 |
public long lastModified() | 获取文件的最后一次修改时间,返回一个时间戳 |
public boolean renameTo(File dest) | 重命名 |
public String[] list() | 返回当前文件目录下的所有文件名 |
public File[] listFiles() | 返回当前文件目录下的所有文件路径 |
public boolean exists() | 判断是否存在 |
public boolean isDirectory() | 判断是否是一个文件目录 |
public boolean isFile() | 判断是否是一个文件 |
public boolean canRead() | 文件是否可读 |
public boolean canWrite() | 文件是否可写 |
public boolean isHidden() | 文件是否隐藏 |
public boolean createNewFile() | 如果该文件不存在创建一个新的文件(路径中上一级文件目录存在) |
public boolean delete() | 删除文件或文件目录(删除文件目录要求文件目录中不能有文件或文件目录) |
public boolean mkdirs() | 创建多级文件目录 |
代码示例:
@Test
public void test2(){
File file2 = new File("Hello.txt");
File file1 = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\Hello.txt");
//获取绝对路径 public String getAbsolutePath()
System.out.println(file1.getAbsolutePath());
//获取相对路径 public String getPath()
System.out.println(file1.getPath());
//获取文件名 public String getName()
System.out.println(file1.getName());
//获取父级文件路径并返回File public File getParentFile()
System.out.println(file1.getParentFile());
//获取文件内容长度 public long length()
System.out.println(file1.length());
//文件的最后一次修改时间 返回的是一个时间戳 public long lastModified()
System.out.println(new Date(file1.lastModified()));
//public boolean renameTo(File dest):重命名File成功返回true
System.out.println(file1.renameTo(new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\Hello.txt")));
System.out.println("----------------");
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getName());
//file2中文件Hello.txt不存在,所以父级路径为null
System.out.println(file2.getParentFile());
System.out.println(file2.length());
System.out.println(new Date(file2.lastModified()));
}
/*输出:
C:\Users\ASUS\IdeaProjects\Ther\src\JavaSE\IO\Hello.txt
C:\Users\ASUS\IdeaProjects\Ther\src\JavaSE\IO\Hello.txt
Hello.txt
C:\Users\ASUS\IdeaProjects\Ther\src\JavaSE\IO
5
Mon Jul 26 22:31:01 CST 2021
true
----------------
C:\Users\ASUS\IdeaProjects\Ther\Hello.txt
Hello.txt
Hello.txt
null
0
Thu Jan 01 08:00:00 CST 1970
*/
@Test
public void test3(){
File file = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther");
//public String[] list():获取当前目录下的所有文件名
String [] list = file.list();
for (String i:
list) {
System.out.println(i);
}
//public File[] listFiles():获取当前目录下的所有文件返回类型为File
File [] files = file.listFiles();
for (File f:
files) {
System.out.println(f);
}
}
//一些常用的判断方法
@Test
public void test4(){
File file = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\Hello.txt");
//public boolean exists():判断是否存在
System.out.println(file.exists());
//public boolean isDirectory():判断该File对象是否是一个文件目录
System.out.println(file.isDirectory());
//public boolean isFile():判断该File对象是否是一个文件
System.out.println(file.isFile());
//public boolean canRead():判断是否可读
System.out.println(file.canRead());
//public boolean canWrite():判断是否可写
System.out.println(file.canWrite());
//public boolean isHidden():判断是否隐藏
System.out.println(file.isHidden());
/*输出:
true
false
true
true
true
false
*/
}
//创建,删除文件或文件目录
@Test
public void test5() throws IOException{
File file1 = new File("Hi.txt");
if(!file1.exists()){
//public boolean createNewFile():文件创建的方法,创建该File文件
file1.createNewFile();
System.out.println("文件创建成功 ");
}else {
//public boolean delete():文件删除的方法
file1.delete();
System.out.println("文件删除成功 ");
}
//父级目录存在
File file2 = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\Hello");
if(!file2.exists()){
//public boolean mkdir():文件目录创建的方法
//返回判断是否创建成功,创建失败有两种情况:1.该文件目录已经存在,2.文件的父级目录不存在
Boolean flag = file2.mkdir();
if (!flag){
file2.mkdirs();
}
System.out.println("文件目录创建成功 ");
}else {
//删除文件目录要求文件目录不能有文件
file2.delete();
}
//父级目录补存在
File file3 = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\Hello\\Hi");
if(!file3.exists()){
Boolean flag = file3.mkdir();
if (!flag){
//public boolean mkdirs():创建多级文件目录的方法
file3.mkdirs();
}
System.out.println("文件目录创建成功 ");
}else {
file3.delete();
}
}
IO流的原理及流的分类
1.Java IO原理
- I/O是input/output的缩写,I/O用于处理设备之间的数据传输
- Java程序中,对于数据的I/O操作是以“流(stream)”的方式进行的
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过 标准的方法 输入或输出数据
2.流的分类
- 按照操作的数据单位分类:
- 字节流(8bit):一般针对二进制文件【视频,音频,图片】
- 字符流(16bit):一般针对文本文件【xml、java、html、txt、md….】
- 按照数据流的流向分类:
- 输入流:从外界(键盘、网络、文件…)读取数据到内存
- 输出流:用于将程序中的数据写出到外界(显示器、文件…)
- 按照流扮演的角色分类:
- 节点流、处理流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
3.IO流体系结构:
4.节点流(字符流&&字节流)
对于流的一般操作步骤:
- 实例化一个文件对象(也可以是匿名的);
- 选择适合操作当前文件对象具体的流(比如文本文件一般使用字符流…);
- 数据的读入;
- 关闭流避免占用过多的内存空间。
注意:为了保证资源可回收。一般使用try-catch-finally来处理相应异常,而不使用throws抛出异常。
4.1 字符流和字节流的区别:
- 读写单位不同:字节流以字节(8Bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi 等),而字符流只能处理字符类型的数据。例如:本文文件,json,html,css,js,xml
注意:只要是处理纯文本数据,就优先考虑使用字符流,除此之外都使用字节流
4.2 字符流的使用:
字符流一般用来处理文本文件。
4.2.1 从文件中读取文本文件,输出到控制台
步骤:
-
先提供一个File类的对象,指明要读出的文件
-
提供具体的流,即提供FileReader的对象,用于数据的写出。注意文件一定要存在,否则会抛出异常。
-
数据的读出
public int read():返回读入的一个字符。如果达到文件末尾,返回-1
-
资源关闭close()
注意:为了保证资源可回收(防止程序前面报错,而流不能正常关闭,占用内存资源)。所以一般使用try-catch-finally而不使用throws抛出异常。
示例代码:
@Test
public void test(){
//1.实例化File对象,指明要操作的文件
File file = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\Hello.txt");
//将文件内容读取到内存中,并输出到控制台
//2.提供具体的流
//为了保证资源可回收。一般使用try-catch-finally而不使用throws抛出异常
FileReader fileReader = null;
try {
//读入的文件一定要存在,否则会报FileNotFoundException异常
fileReader = new FileReader(file);
//3.数据的读入
//public int read():返回读入的一个字符。如果达到文件末尾,返回-1
int data = fileReader.read();
while (data != -1){
System.out.print((char)data);
data = fileReader.read();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.流的关闭操作
if(fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
对read()操作升级:使用read的重载方法(可以每次读取不止一个字符,每次读取一个字符效率太低)
public int read(char cbuf[]) throws IOException :
cbuf : 目标缓冲区,return:返回值为读取的字符长度
@Test
public void test1() throws IOException {
File file = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\Hello.txt");
FileReader fileReader = new FileReader(file);
char[] c = new char[2];
int len;
while ((len = fileReader.read(c)) != -1){
//错误写法:
//输出:hellol
// for (int i = 0; i < c.length; i++) {
// System.out.print(c[i]);
// }
//正确写法1:
//输出:hello
// for (int i = 0; i < len; i++) {
// System.out.print(c[i]);
// }
//错误写法2:
//输出:hellol
// for (char cc:
// c) {
// System.out.print(cc);
// }
//正确的写法2:
String str = new String(c,0,len);
System.out.printf(str);
}
if(fileReader != null){
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.2.2 从内存写入到文件中
步骤:
-
先提供一个File类的对象,指明要写入的文件
-
提供FileWriter的对象,用于数据的写出。
注意在创建FileWriter类的对象的时候,会有构造器为**public FileWriter(File file, boolean append)**append默认为false,写入并替换源文件的内容append == true表示在原文件的基础之上进行写入操作。
-
写入的相关操作:使用public void write(String str)方法
-
资源关闭close()
示例代码:
//从内存写入到文件里
@Test
public void testFileWriter() throws IOException {
//1.提供File类的对象,指明写出到的文件
File file = new File("HelloWrite.txt");
//2.提供FileWriter的对象,用于数据的写出
//public FileWriter(File file, boolean append)
//append默认为false,写入并替换源文件的内容
// append == true表示在原文件的基础之上进行写入操作。
FileWriter fw = new FileWriter(file,true);
//3.写入的操作
fw.write("Hello World\n!!!");
//4.资源关闭
fw.close();
}
4.2.3 从文件A写入到文件B中
注意:使用字符流读取文件内容写入到另一个文件中去,只能是文本文件,不能使用字符流来处理图片,音乐,视频等字节数据,否则读取后的文件打不开。
@Test
public void testFileReaderFileWriter(){
FileReader fr = null;
FileWriter fw = null;
try {
File file = new File("Hello1.txt");
File file1 = new File("Hello2.txt");
//代码可以执行,但复制后的图片打不开
//不能使用字符流来处理图片,音乐,视频等字节数据
// File file = new File("C:\\Users\\ASUS\\IdeaProjects\\Ther\\src\\JavaSE\\IO\\IOStream\\Cat.png");
// File file1 = new File("Hello2.png");
if(file.isFile() == false){
file.createNewFile();
}
fr = new FileReader(file);
fw = new FileWriter(file1);
char[] cbuf = new char[5];
int len;
while ( (len = fr.read(cbuf)) != -1){
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.3 字节流(FileInputStream && FileOutputStream)的使用
字节流一般用来处理非文本类文件,比如:使用字节流来处理文本文件读入到内存中去,可能会出现乱码。
FileInputStream:从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境
FileOutputStream:文件输出流是用于将数据写入文件的输出流。
使用字节流来实现文件的复制操作:
public class FileInputOutStreamTest {
/**
* copyFile() :实现指定路径下文件的复制操作
* @param srcPath :源文件的路径
* @param destPath :复制的文件的路径
*/
public static void copyFile(String srcPath,String destPath){
FileOutputStream fw = null;
FileInputStream fr = null;
try {
File file = new File(srcPath);
File file1 = new File(destPath);
fr = new FileInputStream(file);
fw = new FileOutputStream(file1);
byte[] buf = new byte[1024];
int len;
while ( (len = fr.read(buf)) != -1){
fw.write(buf,0,len);
}
System.out.println("复制成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
copyFile("Cat.png","Hello2.png");
long end = System.currentTimeMillis();
System.out.print("执行的时间为:");
System.out.print(new Date(end - start).getTime()+"ms");
}
}
5.处理流
处理流,就是套接在已有的流的基础上使用
5.1 缓冲流
缓冲流:BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter
作用:提高流的读取、写入速度
5.1.1 缓冲流的使用
public class BufferedTest {
//实现文件的复制
@Test
public void BufferedStreamTest(){
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.创建文件对象
File srcFile = new File("Cat.png");
File destFile = new File("Hello2.png");
//2.造流
//2.1 节点流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//2.2 缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制文件操作:读取、写入
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
}
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:在关闭外层的流的同时,内层流也会自动的关闭。关闭内层流的操作可以省略。
// fos.close();
// fis.close();
}
5.1.2 使用缓冲流和不使用缓冲流来复制文件对比速度
public class speedTest {
public static void BufferedSpeed(String sFile,String dFile){
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.创建文件对象
File srcFile = new File(sFile);
File destFile = new File(dFile);
//2.造流
//2.1 节点流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
//2.2 缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制文件操作:读取、写入
byte[] buffer = new byte[1024];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void FileSpeed(String srcPath,String destPath){
FileOutputStream fw = null;
FileInputStream fr = null;
try {
File file = new File(srcPath);
File file1 = new File(destPath);
fr = new FileInputStream(file);
fw = new FileOutputStream(file1);
byte[] buf = new byte[1024];
int len;
while ( (len = fr.read(buf)) != -1){
fw.write(buf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
//文件流的执行速度
System.out.print("文件流的执行速度:");
long start = System.currentTimeMillis();
FileSpeed("Cat.png","Hello2.png");
long end = System.currentTimeMillis();
System.out.println(new Date(end - start).getTime());
//加上缓冲流之后的速度
System.out.print("缓冲流的执行速度:");
start = System.currentTimeMillis();
BufferedSpeed("Cat.png","Hello2.png");
end = System.currentTimeMillis();
System.out.println(new Date(end - start).getTime());
// 文件流的执行速度:25
// 缓冲流的执行速度:7
}
}
5.2 转换流
转换流:属于字符流
- InputStreamReader:将一个字节的输入流,转换为字符的输入流。
- OutputStreamWriter:将一个字符的输出流,转换为字节的输出流。
作用:提供字节流与字符流之间的转换
解码:字节、字节数组 --> 字符数组、字符串
编码:字符数组、字符串 --> 字节、字节数组
5.2.1 转换流的使用
public class InputStreamReaderTest {
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("Hello1.txt");
// InputStreamReader isr = new InputStreamReader(fis);//系统默认的字符集
//指明了字符集,具体使用哪一个字符集,具体取决于文件保存使用的字符集
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.println(str);
}
isr.close();
}
//综合使用转化流:转换文件格式
// InputStreamReader:将一个字节的输入流,转换为字符的输入流。
// OutputStreamWriter:将一个字符的输出流,转换为字节的输出流。
@Test
public void test2() throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("Hello1.txt"),"UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("Hello2.txt"),"GBK");
char[] cbuf = new char[20];
int len;
while ((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
isr.close();
osw.close();
}
}
5.3 标准的输入、输出流
标准的输入流:System.in(默认从键盘输入)
标准的输出流:System.out(默认从控制台输出)
可以通过System类中的 setIn() / setOut()
5.3.1 使用
/*
例子:转换字母输出为大写,输入e或者exit退出
*/
public static void main(String[] args){
BufferedReader br = null;
try {
InputStreamReader isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
while (true){
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.4 打印流 PrintStream、PrintWriter
打印流:PrintStream、PrintWriter
提供了一系列重载的print()和Println()方法,用于多种数据类型的输出
有自动flush功能
System.out返回的是PrintStream的实例
5.4.1 使用
@Test
public void test(){
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(new File("Hello1.txt"));
ps = new PrintStream(fos,true);
//将标准的输出流(从控制台输出)改到文件中
if (ps != null){
System.setOut(ps);
}
//输出ASCII字符
for (int i = 0; i <= 255; i++) {
System.out.print((char)i);
if (i % 25 == 0){
System.out.println();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null){
try {
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
5.5 数据流
数据流:DataInputStream/DataOutputStream(用于读取和写出基本数据类型、String类的数据)
为了方便的操作java语言的基本数据类型和String的数据,可以使用数据流。
5.5.1 使用(写出数据到文件,从文件读入数据)
@Test
//将数据写入到文件
public void test2(){
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream("data.dat"));
dos.writeUTF("Ther");
dos.flush();
dos.write(21);
dos.flush();
dos.writeBoolean(true);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dos != null){
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//从文件中读出数据,注意一定要是写入的次序
@Test
public void test3(){
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream("data.dat"));
System.out.println("姓名:" + dis.readUTF());
System.out.println("年龄:" + dis.read());
System.out.println("是否为男性:" + dis.readBoolean());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dis != null){
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.6 对象流(ObjectInputStream 和 ObjectOutputStream)
- 作用:用于存储和存取 基本数据类型 数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原出来。
- 序列化:用ObjectOutputStream类保存基本数据类型数据或对象的机制
- 反序列化:用ObjectInputStream类读取基本数据类型或对象的机制
- 不能序列化 static 和 transient修饰的成员变量
5.6.1 对象的序列化
Java对象序列化(Serialize)是指将Java对象写入IO流,反序列化(Deserilize)则是从IO流中恢复该Java对象。
- 对象序列化将程序运行时内存中的对象以字节码的方式保存在磁盘中,或直接通过网络进行传输(例如web中的HttpSession,或者J2EE中的RMI参数及返回值),以便通过反序列化的方式将字节码恢复成对象来使用。
- 所有可能在网络上传输对象的类都应该可序列化,通常分布式应用需要跨平台,跨网络,所以要求所有传递的参数及返回值都可序列化。
- 通常让需要被序列化和的类实现Serializable接口,调用序列化流对象(ObjectOutputStream/ObjectInputStream)的writeObject和readObject就可以实现序列化,
- 另外,通过实现Externlizable接口也可以实现序列化,但是必须要重写writeObject和readObject这两个方法才行。
5.6.2 使用
public class ObjectInputOutputStreamTest {
//读出到文件
//序列化
@Test
public void test(){
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("Object.dat"));
//对象必须implements Serializable
//private static final long serialVersionUID = 4123789163L;要有序列版本号
Person person = new Person("张三",21,true);
oos.writeObject(person);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//反序列化
@Test
public void test1(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("Object.dat"));
System.out.println(ois.readObject().toString());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//Person{name='张三', age=21, sex=true}
}
5.7 随机存取文件流RandomAccessFile
Java IO流详解(三)——RandomAccessFile - 简书 (jianshu.com)
- RadomAccessFile声明在java.io包下,但直接继承于java.lang.Object类。并且它实现了DataInput、DataOutput的两个接口,也就意味着这个类既可以读也可以写。
- RadomAccessFile类支持“随机访问”的方式,程序可以直接到文件的任意地方来读、写文件
- 支持只访问文件的部分内容
- 可以向已存在的文件后追加内容
- RadomAccessFile 对象包含一个记录指针,用以标识当前读写处的位置
- long getFilePointer():获取文件记录指针的当前位置;
- void seek(long pos):将文件记录指针定位到pos位置。
RandomAccessFile的构造函数
RandomAccessFile类有两个构造函数,其实这两个构造函数基本相同,只不过是指定文件的形式不同——一个需要使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,一共有4种模式。
**“r” : ** 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw": 打开以便读取和写入。
"rws": 打开以便读取和写入。相对于 “rw”,“rws” 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
"rwd" : 打开以便读取和写入,相对于 “rw”,“rwd” 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
使用
public class RandomAccessFileTest {
@Test
public void test() throws FileNotFoundException {
RandomAccessFile raf = null;
RandomAccessFile raf_w = null;
try {
raf = new RandomAccessFile("Hello1.txt","r");
raf_w = new RandomAccessFile("Hello2.txt","rw");
byte[] buffer = new byte[1024];
int len;
while((len = raf.read(buffer)) != -1){
raf_w.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf != null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (raf_w != null){
try {
raf_w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}