文章目录
3.3.2 字节流
3.3.2.1 FileOutputStream类(重点)
(1)基本概念
java.io.FileOutputStream类主要用于将图像数据之类的原始字节流写入到输出流中。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
FileOutputStream(String name) | 根据参数指定的文件名来构造对象 |
FileOutputStream(String name,boolean append) | 以追加的方式根据参数指定的文件名来构造对象 |
void write(int b) | 将指定字节写入此文件输出流 |
void write(byte[] b, int off, int len) | 将指定字节数组中从偏移量off开始的len个字节写入此文件输出流 |
void write(byte[] b) | 将 b.length 个字节从指定字节数组写入此文件输出流中 |
void flush() | 刷新此输出流并强制写出任何缓冲的输出字节 |
void close() | 关闭流对象并释放有关的资源 |
3.3.2.2 FileInputStream类(重点)
(1)基本概念
java.io.FileInputStream类主要用于从输入流中以字节流的方式读取图像数据等。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
FileInputStream(String name) | 根据参数指定的文件路径名来构造对象 |
int read() | 从输入流中读取单个字节的数据并返回,返回-1表示读取到末尾 |
int read(byte[] b, int off, int len) | 从此输入流中将最多len个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾 |
int read(byte[] b) | 从此输入流中将最多 b.length 个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾 |
void close() | 关闭流对象并释放有关的资源 |
int available() | 获取输入流所关联文件的大小 |
编程实现两个文件之间的拷贝功能。
//获取当前系统距离基准时间的毫秒数
long g1=System.currentTimeMillis();
FileInputStream fis= null;
FileOutputStream fos= null;
try {
//1.创建FileInputStream类型的对象并与文件关联
fis = new FileInputStream("e:/22.MP4");
//2.创建FileOutStream类型的对象并与文件关联
fos = new FileOutputStream("e:/022.mp4");
//3.向输入流中读取文件并写入输出流中
System.out.println("拷贝文件中");
//方式一:以单个字节为单位进行拷贝,也就是读取一个字节再写一个字节
//缺点:文件稍大时,拷贝的效率较低
/*int res=0;
while ((res=fis.read())!=-1) {
fos.write(res);
}*/
//方式二:准备一个和文件大小相同的缓存区,一次性将文件中的数据内容读取到缓存区然后一次性写入
//缺点:若文件太大,无法申请和数据内容一样大的缓存区,真实物理内存不足
/* int len = fis.available();
System.out.println("文件的大小为:"+len); //12945408
byte[] bArr=new byte[len];
int res=fis.read(bArr);
System.out.println("实际获取到的文件大小是:"+res); //12945408
fos.write(bArr);*/
//方式三:准备一个适量大小的缓存区,分多次将文件拷贝
byte[] bArr=new byte[1024];
int res=0;
while ((res=fis.read(bArr))!=-1) {
//将大小为res的文件按存放到下标为0开始的位置
fos.write(bArr,0,res);
}
System.out.println("拷贝成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流对象并释放相关资源
try {
if (null!=fis){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (null!=fos) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
long g2=System.currentTimeMillis();
System.out.println("使用文件流拷贝视频的时间是:"+(g2-g1)); //555
3.3.2.3 BufferedOutputStream类(重点)
(1)基本概念
java.io.BufferedOutputStream类主要用于描述缓冲输出流,此时不用为写入的每个字节调用底层系统。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
BufferedOutputStream(OutputStream out) | 根据参数指定的引用来构造对象 |
BufferedOutputStream(OutputStream out, int size) | 根据参数指定的引用和缓冲区大小来构造对象 |
void write(int b) | 写入单个字节 |
void write(byte[] b, int off, int len) | 写入字节数组中的一部分数据 |
void write(byte[] b) | 写入参数指定的整个字节数组 |
void flush() | 刷新流 |
void close() | 关闭流对象并释放有关的资源 |
3.3.2.4 BufferedInputStream类(重点)
(1)基本概念
java.io.BufferedInputStream类主要用于描述缓冲输入流。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
BufferedInputStream(InputStream in) | 根据参数指定的引用构造对象 |
BufferedInputStream(InputStream in, int size) | 根据参数指定的引用和缓冲区大小构造对象 |
int read() | 读取单个字节 |
int read(byte[] b, int off, int len) | 读取len个字节 |
int read(byte[] b) | 读取b.length个字节 |
void close() | 关闭流对象并释放有关的资源 |
//获取当前系统距离基准时间的毫秒数
long g1=System.currentTimeMillis();
BufferedInputStream bis= null;
BufferedOutputStream bos= null;
try {
//1.创建一个BufferedInputStream类型的对象并关联对象
bis = new BufferedInputStream(new FileInputStream("e:/22.mp4"));//自带缓存大小为8192
//2.创建一个BufferedOutputStream类型的对象并关联对象
bos = new BufferedOutputStream(new FileOutputStream("e:/022.mp4"));
//3.不断的从输入流中读取数据并写入输入流中
System.out.println("正在拷贝中...");
byte[] bArr=new byte[1024];
int res=0;
while ((res=bis.read(bArr))!=-1) {
bos.write(bArr,0,res);
}
System.out.println("拷贝成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流对象并释放相关资源
if (null!=bos) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(null!=bis) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long g2=System.currentTimeMillis();
System.out.println("使用缓冲流拷贝视频的时间是:"+(g2-g1)); //116
}
3.3.2.5 PrintStream类
(1)基本概念
java.io.PrintStream类主要用于更加方便地打印各种数据内容。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
PrintStream(OutputStream out) | 根据参数指定的引用来构造对象 |
void print(String s) | 用于将参数指定的字符串内容打印出来 |
void println(String x) | 用于打印字符串后并终止该行 |
void flush() | 刷新流 |
void close() | 用于关闭输出流并释放有关的资源 |
案例题目
不断地提示用户输入要发送的内容,若发送的内容是"bye"则聊天结束,否则将用户输入的内容写入到文件d:/a.txt中。
要求使用BufferedReader类来读取键盘的输入 System.in代表键盘输入
要求使用PrintStream类负责将数据写入文件
package demo01;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PrintStreamChatTest {
public static void main(String[] args) {
//由手册可知:构造对象的实参需要reader类型的抽象类 字符流
//由手册可知:键盘输入是System.in类型的对象,FileOutputStream 字节流
//所以需要只用转换流进行转换:将字节流转换为字符流:InputStreamReader
BufferedReader br=null;
PrintStream ps=null;
try {
br=new BufferedReader(new InputStreamReader(System.in));
ps=new PrintStream(new FileOutputStream("e:/a.txt",true)); //追加内容,将不再清空文件原有的数据内容
//声明一个boolean类型的变量进行发送方的区分
boolean flag=true;
while (true) {
//1.提示用户输入要发送的内容并使用变量记录
System.out.println("请"+(flag?" 周扬 ":" 阿七 ")+"输入要发送的内容:");
String str=br.readLine();
//2.判断用户输入的内容是否为"bye",若是则结束聊天
if ("bye".equals(str)) {
System.out.println("聊天结束");
break;
}
//若不是则将聊天内容写入关联文件中
//获取当前时间并转换格式
Date d1=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ps.println(sdf.format(d1)+(flag?" 周扬说:":" 阿七说:")+str);
flag=!flag;
}
ps.println(); //空格
ps.println();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流并释放有关资源
ps.close();
if (null!=br) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.3.2.6 DataOutputStream类(了解)
(1)基本概念
java.io.DataOutputStream类主要用于以适当的方式将基本数据类型写入输出流中。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
DataOutputStream(OutputStream out) | 根据参数指定的引用构造对象 OutputStream类是个抽象类,实参需要传递子类对象 |
void writeInt(int v) | 用于将参数指定的整数一次性写入输出流,优先写入高字节 |
void close() | 用于关闭文件输出流并释放有关的资源 |
package demo01;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamTest {
public static void main(String[] args) {
DataOutputStream dos= null;
try {
//1.创建对象并关联
dos = new DataOutputStream(new FileOutputStream("e:/a.txt"));
//2.准备一个整数数据66,并写入输出流
int num=66;
// dos.write(num); //一个字节
dos.writeInt(num); //int 四个字节
System.out.println("数据写入成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭流对象
if (null!=dos) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.3.2.7 DataInputStream类(了解)
(1)基本概念
java.io.DataInputStream类主要用于从输入流中读取基本数据类型的数据。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
DataInputStream(InputStream in) | 根据参数指定的引用来构造对象 InputStream类是抽象类,实参需要传递子类对象 |
int readInt() | 用于从输入流中一次性读取一个整数数据并返回 |
void close() | 用于关闭文件输出流并释放有关的资源 |
package demo01;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataInputStreamTest {
public static void main(String[] args) {
DataInputStream dis= null;
try {
//创建对象关联文件
dis = new DataInputStream(new FileInputStream("e:/a.txt"));
//读取文件并打印内容
int i = dis.readInt();
// int i=dis.read() //读取一个字节
System.out.println("读取到的内容是:"+i); //66
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流对象
if (null!=dis){
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.3.2.8 ObjectOutputStream类(重点)
(1)基本概念
-
java.io.ObjectOutputStream类主要用于将一个对象的所有内容整体写入到输出流中。
-
只能将支持 java.io.Serializable 接口的对象写入流中。
-
类通过实现 java.io.Serializable 接口以启用其序列化功能。
-
所谓序列化主要指将一个对象需要存储的相关信息有效组织成字节序列的转化过程。
package demo01; import java.io.Serializable; public class User implements Serializable { //在序列化的过程中要自定一个序列化的版本号 是序列化与反序列化建立的一种关系 private static final long serialVersionUID = -352725807851624757L; //序列号版本 private String userName; private int userPassword; private transient int phoneNum; //该成员变量不参与序列化与反序列化 transient ....... } }
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
ObjectOutputStream(OutputStream out) | 根据参数指定的引用来构造对象 |
void writeObject(Object obj) | 用于将参数指定的对象整体写入到输出流中 |
void close() | 用于关闭输出流并释放有关的资源 |
public class ObjectOutputStreamTest {
public static void main(String[] args) {
ObjectOutputStream oot= null;
try {
//1.创建对象并关联文件
oot = new ObjectOutputStream(new FileOutputStream("e:/a.txt"));
//2.构造要写入的对象并传参
User user=new User("周扬",12345,119120110);
//3.写入对象
oot.writeObject(user);
System.out.println("对象写入成功"); //乱码
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭流对象
if (null!=oot) {
try {
oot.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.3.2.9 ObjectInputStream类(重点)
(1)基本概念
java.io.ObjectInputStream类主要用于从输入流中一次性将对象整体读取出来。
所谓反序列化主要指将有效组织的字节序列恢复为一个对象及相关信息的转化过程。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
ObjectInputStream(InputStream in) | 根据参数指定的引用来构造对象 |
Object readObject() | 主要用于从输入流中读取一个对象并返回 无法通过返回值来判断是否读取到文件的末尾 |
void close() | 用于关闭输入流并释放有关的资源 |
public class ObjectInputStreamTest {
public static void main(String[] args) {
ObjectInputStream ois= null;
try {
//1.构建对象并关联文件
ois = new ObjectInputStream(new FileInputStream("e:/a.txt"));
//2.向输入流中读取一个对象
Object obj=ois.readObject();
System.out.println("读取的内容是:"+obj);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
//3.关闭流对象
if (null!=ois) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
(3) 序列化版本号
序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的
serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化
版本不一致的异常(InvalidCastException)。
public class User implements Serializable {
//在序列化的过程中要自定一个序列化的版本号 是序列化与反序列化建立的一种关系
private static final long serialVersionUID = -352725807851624757L; //序列号版本
(4)transient关键字
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括
在串行化的表示中,然而非transient型的变量是被包括进去的。
private transient int phoneNum; //该成员变量不参与序列化与反序列化 transient
(5)经验的分享
当希望将多个对象写入文件时,通常建议将多个对象放入一个集合中,然后将集合这个整体看做一个对象写入输出流中,此时只需要调用
一次readObject方法就可以将整个集合的数据读取出来,从而避免了通过返回值进行是否达到文件末尾的判断。
3.4 RandomAccessFile类
(1)基本概念
java.io.RandomAccessFile类主要支持对随机访问文件的读写操作。
(2)常用的方法
方法声明 | 功能介绍 |
---|---|
RandomAccessFile(String name, String mode) | 根据参数指定的名称和模式构造对象 r: 以只读方式打开 rw:打开以便读取和写入 rwd:打开以便读取和写入,同步文件内容的更新 rws:打开以便读取和写入,同步文件内容和元数据的更新 |
int read() | 读取单个字节的数据 |
void seek(long pos) | 用于设置从此文件的开头开始测量的文件指针偏移量 |
void write(int b) | 将参数指定的单个字节写入 |
void close() | 用于关闭流并释放有关的资源 |
package demo01;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.RandomAccess;
public class RandomAccessFileTest {
public static void main(String[] args) {
RandomAccessFile ras = null;
try {
//1.创建对象关联文件
ras = new RandomAccessFile("e:/a.txt", "rw");
//2.随机访问文件内容 文件内容a: aellhello
//距离文件开头位置的偏移量,从文件开头位置a向后偏移4个字节(h)
ras.seek(4);
int i = ras.read();
System.out.println("读取到的单个字符是:" + (char)i); //h 此时指向e
i=ras.read();
System.out.println("读取到的单个字符是:"+(char)i); //e 此时指向l
//对文件进行写操作
ras.write('q'); //执行该代码后覆盖了字母l
System.out.println("数据写入成功!"); //aellheqlo
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭流对象
if (null != ras) {
try {
ras.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}