Java中四大IO抽象类
InputStream/OutputStream和Reader/Writer类是所有IO流类的抽象父类,我们有必要简单了解一下这个四个抽象类的作用。然后,通过它们具体的子类熟悉相关的用法。
InputStream
此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。 数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类。继承自InputSteam的流都是用于向程序中输入数据,且数据的单位为字节( 8 bit)。
int read():读取一个字节的数据,并将字节的值作为int类型返回( 0 - 255 之间的一个值)。如果未读出字节则返回- 1 (返回值为- 1 表示读取结束)。
void close():关闭输入流对象,释放相关系统资源。
OutputStream
此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到某个目的地。
void write(intn):向目的地中写入一个字节。
void close():关闭输出流对象,释放相关系统资源。
Reader
Reader用于读取的字符流抽象类,数据单位为字符。
int read(): 读取一个字符的数据,并将字符的值作为int类型返回( 0 - 65535 之间的一个值,即Unicode值)。如果未读出字符则返回- 1 (返回值为- 1 表示读取结束)。
void close() : 关闭流对象,释放相关系统资源。
Writer
Writer用于输出的字符流抽象类,数据单位为字符。
void write(intn): 向输出流中写入一个字符。
void close() : 关闭输出流对象,释放相关系统资源。
Java中流的概念细分
按流的方向分类:
*输入流:数据流从数据源到程序(以InputStream、Reader结尾的流)。
* 输出流:数据流从程序到目的地(以OutPutStream、Writer结尾的流)。
按处理的数据单元分类:
* 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、FileOutputStream。
* 字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如FileReader、FileWriter。
按处理对象不同分类:
* 节点流:可以直接从数据源或目的地读写数据,如FileInputStream、FileReader、DataInputStream等。
* 处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流。
节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。
Java中IO流类的体系
Java为我们提供了多种多样的IO流,我们可以根据不同的功能及性能要求挑选合适的IO流。
从上图发现,很多流都是成对出现的,比如:FileInputStream/FileOutputStream,显然是对文件做输入和输出操作的。我们下面简单做个总结:
* 1 .InputStream/OutputStream
字节流的抽象类。
* 2 .Reader/Writer
字符流的抽象类。
* 3 .FileInputStream/FileOutputStream
节点流:以字节为单位直接操作“文件”。
* 4 .ByteArrayInputStream/ByteArrayOutputStream
节点流:以字节为单位直接操作“字节数组对象”。
* 5 .ObjectInputStream/ObjectOutputStream
处理流:以字节为单位直接操作“对象”。
* 6 .DataInputStream/DataOutputStream
处理流:以字节为单位直接操作“基本数据类型与字符串类型”。
* 7 .FileReader/FileWriter
节点流:以字符为单位直接操作“文本文件”(注意:只能读写文本文件)。
* 8 .BufferedReader/BufferedWriter
处理流:将Reader/Writer对象进行包装,增加缓存功能,提高读写效率。
* 9 .BufferedInputStream/BufferedOutputStream
处理流:将InputStream/OutputStream对象进行包装,增加缓存功能,提高读写效率。
* 10 .InputStreamReader/OutputStreamWriter
处理流:将字节流对象转化成字符流对象。
* 11 .PrintStream
处理流:将OutputStream进行包装,可以方便地输出字符,更加灵活。
IO流入门案例
1 第一个简单的IO流程序
当程序需要读取数据源的数据时,就会通过IO流对象开启一个通向数据源的流,通过这个IO流对象的相关方法可以顺序读取数据源中的数据。
package com.yoostar.coms;
import java.io.FileInputStream;
public class FirstDemo {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建字节输入流对象
fis = new FileInputStream("d:/a.txt");
int s1 = fis.read(); // 打印输入字符 a 对应的 ascii 码值 97
int s2 = fis.read(); // 打印输入字符 b 对应的 ascii 码值 98
int s3 = fis.read(); // 打印输入字符 c 对应的 ascii 码值 99
int s4 = fis.read(); // 由于文件内容已经读取完毕,则返回 - 1
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
2 改造入门案例
package com.yoostar.coms;
import java.io.FileInputStream;
public class SecondDemo {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建字节输入流对象
fis = new FileInputStream("d:/a.txt");
StringBuilder sb = new StringBuilder();
int temp = 0;
while ((temp = fis.read()) != -1) {
System.out.println(temp);
sb.append((char) temp);
}
System.out.println(sb);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
File类的使用
File类简介
File类的作用
File类是Java提供的针对磁盘中的文件或目录转换对象的包装类。一个File对象而可以代表一个文件或目录,File对象可以实现获取文件和目录属性等功能,可以实现对文件和目录的创建,删除等功能。
File类操作目录与文件的常用方法
针对文件操作的方法
createNewFile()//创建新文件。
delete()//直接从磁盘上删除
exists()//查询磁盘中的文件是否存在
getAbsolutePath()//获取绝对路径
getPath()//获取相对路径
getName()//获取文件名 相当于调用了一个toString方法。
isFile()//判断是否是文件
length()//查看文件中的字节数
isHidden()//测试文件是否被这个抽象路径名是一个隐藏文件。
针对目录操作的方法
exists()//查询目录是否存在
isDirectory()//判断当前路径是否为目录
mkdir()//创建目录
mkdirs()//递归创建目录
getParentFile()//获取当前目录的父级目录。
list()//返回一个字符串数组,包含目录中的文件和目录的路径名。
listFiles//返回一个File数组,表示用此抽象路径名表示的目录中的文件。
File类的基本使用
操作文件
package com.yoostar.coms;
import java.io.File;
public class FileDemo {
public static void main(String[] args) throws Exception {
//创建 File 对象
File file = new File("d:/aa.txt");
System.out.println(file.createNewFile());
// System.out.println(file.delete());
// System.out.println(file.exists());
// System.out.println(file.getName());
// System.out.println(file.isFile());
// System.out.println(file.isHidden());
}
}
package com.yoostar.coms;
import java.io.File;
public class DirectoryDemo {
public static void main(String[] args) {
//创建 File 对象
// File file = new File("d:/b/c");
// System.out.println(file.mkdir());
// System.out.println(file.mkdirs());
// System.out.println(file.exists());
// System.out.println(file.isDirectory());
// System.out.println(file.getParent());
// System.out.println(file.getParentFile().getName());
File file2 = new File("d:/");
String[] arr = file2.list();
for (String temp : arr) {
System.out.println(temp);
}
System.out.println("-----------------------");
File[] arr2 = file2.listFiles();
for (File temp : arr2) {
System.out.println(temp);
}
}
}
常用流对象
文件字节流
FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。Java也提供了FileReader专门读取文本文件。<br>
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。Java也提供了FileWriter专门写入文本文件。
文件字节输入流
package com.yoostar.coms;
import java.io.FileInputStream;
public class FileStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("d:/sxt.jpg");
int temp = 0;
while ((temp = fis.read()) != -1) {
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
文件字节输出流
package com.yoostar.coms.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("d:/1.png"); //创建文件字节输出流对象
fos = new FileOutputStream("d:/2.png");
int temp = 0;
while ((temp = fis.read()) != -1) {
fos.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过缓冲区提高读写效率
方式一
通过创建一个指定长度的字节数组作为缓冲区,以此来提高IO流的读写效率。该方式适用于读取较大图片时的缓冲区定义。注意:缓冲区的长度一定是 2 的整数幂。一般情况下1024 长度较为合适。
package com.yoostar.coms.util.excel;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamBuffedDemo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("d:/1.png");
//创建文件字节输出流对象
fos = new FileOutputStream("d:/3.png");
//创建一个缓冲区,提高读写效率
byte[] buff = new byte[1024];
int temp = 0;
while ((temp = fis.read(buff)) != -1) {
fos.write(buff, 0, temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
方式二
通过创建一个字节数组作为缓冲区,数组长度是通过输入流对象的available()返回当前文件的预估长度来定义的。在读写文件时,是在一次读写操作中完成文件读写操作的。注意:如果文件过大,那么对内存的占用也是比较大的。所以大文件不建议使用该方法。
package com.yoostar.coms;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamBuffer2Demo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建文件字节输入流对象
fis = new FileInputStream("d:/itbz.jpg");
//创建文件字节输出流对象
fos = new FileOutputStream("d:/cc.jpg");
//创建一个缓冲区,提高读写效率
byte[] buff = new byte[fis.available()];
fis.read(buff);
//将数据从内存中写入到磁盘中。
fos.write(buff);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过字节缓冲流提高读写效率
Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。
当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷新时再一次性的读取到程序或写入目的地。 因此,缓冲流还是很重要的,我们在IO操作时记得加上缓冲流来提升性能。`BufferedInputStream`和`BufferedOutputStream`这两个流是缓冲字节流,通过内部缓存数组来提高操作流的效率。
package com.yoostar.coms;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileStreamBuffed3Demo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream("d:/itbz.jpg");
bis = new BufferedInputStream(fis);
fos = new FileOutputStream("d:/ff.jpg");
bos = new BufferedOutputStream(fos);
//缓冲流中的 byte 数组长度默认是 8192
int temp = 0;
while ((temp = bis.read()) != -1) {
bos.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//注意:关闭流顺序:"后开的先关闭"
if (bis != null) {
bis.close();
}
if (fis != null) {
fis.close();
}
if (bos != null) {
bos.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
文件字符流
前面介绍的文件字节流可以处理所有的文件,如果我们处理的是文本文件,也可以使用文件字符流,它以字符为单位进行操作。
文件字符输入流
package com.yoostar.coms;
import java.io.FileReader;
public class FileReaderDemo {
public static void main(String[] args) {
FileReader frd = null;
try {
//创建文件字符输入流对象
frd = new FileReader("d:/a.txt");
int temp = 0;
while ((temp = frd.read()) != -1) {
System.out.println((char) temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (frd != null) {
frd.close();
}
} catch (
Exception e) {
e.printStackTrace();
}
}
}
}
文件字符输出流
package com.yoostar.coms;
import java.io.FileWriter;
public class FileWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
FileWriter fw2 = null;
try {
//创建字符输出流对象
fw = new FileWriter("d:/sxt.txt");
fw.write("你好尚学堂\r\n");
fw.write("你好 Oldlu\r\n");
fw.flush();
// 默认是覆盖文件内容,如果设置为true 则在末尾进行拼接
fw2 = new FileWriter("d:/sxt.txt", true);
fw2.write("何以解忧\r\n 唯有尚学堂");
fw2.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fw != null) {
fw.close();
}
if (fw2 != null) {
fw2.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
使用字符流实现文本文件的拷贝处理
package com.yoostar.coms;
import java.io.FileReader;
import java.io.FileWriter;
public class FileCopyTools2 {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("d:/2.txt");
fw = new FileWriter("d:/3.txt");
char[] buffer = new char[1024];
int temp = 0;
while ((temp = fr.read(buffer)) != -1) {
fw.write(buffer, 0, temp);
}
fw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fr != null) {
fr.close();
}
if (fw != null) {
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字符缓冲流
`BufferedReader/BufferedWriter`增加了缓存机制,大大提高了读写文本文件的效率。
字符输入缓冲流
BufferedReader是针对字符输入流的缓冲流对象,提供了更方便的按行读取的方法:`readLine()`;在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.FileReader;
public class BufferedReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader("d:/sxt.txt");
br = new BufferedReader(fr);
String temp = "";
while ((temp = br.readLine()) != null) {
System.out.println(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (fr != null) {
fr.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字符输出缓冲流
BufferedWriter是针对字符输出流的缓冲流对象,在字符输出缓冲流中可以使用`newLine()`;方法实现换行处理。
package com.yoostar.coms;
import java.io.BufferedWriter;
import java.io.FileWriter;
public class BufferedWriterDemo {
public static void main(String[] args) {
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter("d:/sxt2.txt");
bw = new BufferedWriter(fw);
bw.write("你好尚学堂");
bw.write("你好 Oldlu");
bw.newLine();
bw.write("何以解忧");
bw.newLine();
bw.write("唯有尚学堂");
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
if (fw != null) {
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过字符缓冲流实现文本文件的拷贝
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class FileCopyTools3 {
public static void main(String[] args) {
copyFile("d:/2.txt", "d:/22.txt");
}
/**
* 23
* 基于字符流缓冲流实现文件拷贝
*/
public static void copyFile(String src, String des) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(src));
bw = new BufferedWriter(new FileWriter(des));
String temp = "";
while ((temp = br.readLine()) != null) {
bw.write(temp);
bw.newLine();
}
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过字符缓冲流为文件中的内容添加行号
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class LineNumberDemo {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader("d:/sxt2.txt"));
bw = new BufferedWriter(new FileWriter("d:/sxt3.txt"));
String temp = "";
int i = 1;
while ((temp = br.readLine()) != null) {
bw.write(i + "," + temp);
bw.newLine();
i++;
}
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
转换流
`InputStreamReader/OutputStreamWriter`用来实现将字节流转化成字符流。比如,如下场景:
>System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符流BufferedReader特有的方法readLine(),但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个Reader对象,这时候我们的转换流InputStreamReader就派上用场了。而System.out也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的write(Stringstr)方法,所以我们要使用OutputStreamWriter将字节流转化为字符流。(`还可以解决中文乱码的问题`)
通过转换流实现键盘输入屏幕输出
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class ConvertStream {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
while (true) {
bw.write("请输入:");
bw.flush();
String input = br.readLine();
if ("exit".equals(input)) {
break;
}
bw.write("你输入的是:" + input);
bw.newLine();
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
if (br != null) {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
通过字节流读取文本文件并添加行号
package com.yoostar.coms;
import java.io.*;
public class LineNumberDemo2 {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
//可以通过执行编码防止出现中午乱码
br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/sxt.txt"), "utf-8"));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/sxt3.txt"), "utf-8"));
String temp = "";
int i = 1;
while ((temp = br.readLine()) != null) {
bw.write(i + "," + temp);
bw.newLine();
i++;
}
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字符输出流
在Java的IO流中专门提供了用于字符输出的流对象PrintWriter。该对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符串,并且可通过println();方法实现自动换行。
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class LineNumberDemo3 {
public static void main(String[] args) {
BufferedReader br = null;
PrintWriter pw = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/sxt.txt")));
pw = new PrintWriter("d:/sxt4.txt");
String temp = "";
int i = 1;
while ((temp = br.readLine()) != null) {
pw.println(i + "," + temp);
i++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (pw != null) {
pw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字节数组流
`ByteArrayInputStream和ByteArrayOutputStream`经常用在需要流和数组之间转化的情况!比如需要把视频,音频写成一个字节数组在进行数据传输
字节数组输入流
说白了,FileInputStream是把文件当做数据源。ByteArrayInputStream则是把内存中的”字节数组对象”当做数据源。
package com.yoostar.coms;
import java.io.ByteArrayInputStream;
public class ByteArrayInputDemo {
public static void main(String[] args) {
byte[] arr = "abcdefg".getBytes();
ByteArrayInputStream bis = null;
StringBuilder sb = new StringBuilder();
try {
//该构造方法的参数是一个字节数组,这个字节数组就是数据源
bis = new ByteArrayInputStream(arr);
int temp = 0;
while ((temp = bis.read()) != -1) {
sb.append((char) temp);
}
System.out.println(sb.toString());
} finally {
try {
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
字节数组输出流
package com.yoostar.coms;
public class ByteArrayOutputDemo {
public static void main(String[] args) {
ByteArrayOutputStream bos = null;
try {
StringBuilder sb = new StringBuilder();
bos = new ByteArrayOutputStream();
bos.write('a');
bos.write('b');
bos.write('c');
byte[] arr = bos.toByteArray();
for (int i = 0; i < arr.length; i++) {
sb.append((char) arr[i]);
}
System.out.println(sb);
} finally {
try {
if (bos != null) {
bos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
将二进制数据转换成字节数组在写入到新的文件中
package com.xiyan;
import java.io.*;
/**
* @author: Bright
* @date: Created in 2022/2/22 0022 14:01
* @Description:
*/
public class Test {
public static void main(String[] args) {
BufferedInputStream bis = null;
ByteArrayOutputStream bos = null;
BufferedOutputStream bufferedOutputStream = null;
try {
bis = new BufferedInputStream(new FileInputStream("d:\\文档.docx"));
bos = new ByteArrayOutputStream();
bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("d:\\ss.docx"));
int temp;
while ((temp = bis.read()) != -1) {
bos.write(temp);
}
//写入字节数组
byte[] bytes = bos.toByteArray();
//输入到新文件
bufferedOutputStream.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != bufferedOutputStream) {
bufferedOutputStream.close();
}
if (null != bos) {
bos.close();
}
if (null != bis) {
bis.close();
}
} catch (Exception e) {
}
}
}
}
数据流
数据输出流
package com.yoostar.coms;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class DataOutputDemo {
public static void main(String[] args) {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/data.txt")));
dos.writeChar('a');
dos.writeInt(10);
dos.writeDouble(Math.random());
dos.writeBoolean(true);
dos.writeUTF("你好尚学堂");
dos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dos != null) {
dos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
数据输入流
package com.yoostar.coms;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class DataInputDemo {
public static void main(String[] args) {
DataInputStream dis = null;
try {
dis = new DataInputStream(new BufferedInputStream(new FileInputStream("d:/data.txt")));
//直接读取数据,注意:读取的顺序要与写入的顺序一致,否则不能正确读 取数据。
System.out.println("char: " + dis.readChar());
System.out.println("int: " + dis.readInt());
System.out.println("double: " + dis.readDouble());
System.out.println("boolean: " + dis.readBoolean());
System.out.println("String: " + dis.readUTF());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
} catch (
Exception e) {
e.printStackTrace();
}
}
}
}
对象流
对象的本质是用来组织和存储数据的,对象本身也是数据。那么,能不能将对象存储到硬盘上的文件中呢?能不能将对象通过网络传输到另一个电脑呢?我们可以通过序列化和反序列化来实现这些需求。
Java对象的序列化和反序列化
序列化和反序列化是什么
当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。把Java对象转换为字节序列的过程称为 **对象的序列化** 。把字节序列恢复为Java对象的过程称为 **对象的反序列化** 。
对象序列化的作用有如下两种:
* 持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
* 网络通信: 在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。
序列化涉及的类和接口
`ObjectOutputStream`代表对象输出流,它的`writeObject(Objectobj)方法可对参数指定的obj对象进行序列化`,把得到的字节序列写到一个目标输出流中。`ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列`,再把它们反序列化为一个对象,并将其返回。只有实现了`Serializable接口的类的对象才能被序列化`。Serializable接口是一个空接口,只起到标记作用。
操作基本数据类型
我们前边学到的数据流只能实现对基本数据类型和字符串类型的读写,并不能对Java对象进行读写操作(字符串除外),但是在对象流中除了能实现对基本数据类型进行读写操作以外,还可以对Java对象进行读写操作。
写出基本数据类型数据
package com.yoostar.coms;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamBasicTypeDemo {
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("d:/sxt5.txt")));
oos.writeInt(10);
oos.writeDouble(Math.random());
oos.writeChar('a');
oos.writeBoolean(true);
oos.writeUTF("你好 Oldlu");
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
读取基本数据类型数据
package com.yoostar.coms;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ObjectInputStreamBasicTypeDemo {
public static void main(String[] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("d:/sxt5.txt")));
//必须要按照写入的顺序读取数据
System.out.println("int: " + ois.readInt());
System.out.println("double: " + ois.readDouble());
System.out.println("char: " + ois.readChar());
System.out.println("boolean: " + ois.readBoolean());
System.out.println("String: " + ois.readUTF());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
操作对象
将对象序列化到文件
ObjectOutputStream可以将一个内存中的Java对象通过序列化的方式写入到磁盘的文件中。`被序列化的对象必须要实现Serializable序列化接口,否则会抛出异常`。
创建对象
package com.yoostar.coms;
import java.io.Serializable;
public class Users implements Serializable {
private int userid;
private String username;
private String userage;
public Users(int userid, String username, String userage) {
this.userid = userid;
this.username = username;
this.userage = userage;
}
public Users() {
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserage() {
return userage;
}
public void setUserage(String userage) {
this.userage = userage;
}
}
序列化对象
package com.yoostar.coms;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamObjectTypeDemo {
public static void main(String[] args) {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("d:/sxt6.txt"));
Users users = new Users(1, "Oldlu", "18");
oos.writeObject(users);
oos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
将对象反序列化到内存中
package com.yoostar.coms;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class ObjectInputStreamObjectTypeDemo {
public static void main(String[] args) {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("d:/sxt6.txt"));
Users users = (Users) ois.readObject();
System.out.println(users.getUserid() + "\t" + users.getUsername() + "\t " + users.getUserage());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ois != null) {
ois.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
File类在IO中的作用
当以文件作为数据源或目标时,除了可以使用字符串作为文件以及位置的指定以外,我们也可以使用File类指定。
package com.yoostar.coms;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class FileInIODemo {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(new File("d:/sxt.txt")));
bw = new BufferedWriter(new FileWriter(new File("d:/sxt8.txt")));
String temp = "";
int i = 1;
while ((temp = br.readLine()) != null) {
bw.write(i + "," + temp);
bw.newLine();
i++;
}
bw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (bw != null) {
bw.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
总结
输入流:数据源到程序(InputStream、Reader读进来)。
* 输出流:程序到目的地(OutPutStream、Writer写出去)。
* 按流的处理数据单元分类:
* 字节流:按照字节读取数据(InputStream、OutputStream)。
* 字符流:按照字符读取数据(Reader、Writer)。
* 按流的功能分类:
* 节点流:可以直接从数据源或目的地读写数据。
* 处理流:不直接连接到数据源或目的地,是处理流的流。通过对其他流的处理提高程序的性能。
* IO的四个基本抽象类:InputStream、OutputStream、Reader、Writer
* InputStream的实现类:
* FileInputStream
* ByteArrayInutStream
* BufferedInputStream
* DataInputStream
* ObjectInputStream
* OutputStream的实现类:
* FileOutputStream
* ByteArrayOutputStream
* BufferedOutputStream
* DataOutputStream
* ObjectOutputStream
* PrintStream
* Reader的实现类
* FileReader
* BufferedReader
* InputStreamReader
* Writer的实现类
* FileWriter
* BufferedWriter
* OutputStreamWriter
* 把Java对象转换为字节序列的过程称为对象的序列化。
* 把字节序列恢复为Java对象的过程称为对象的反序列化。