javase-3

、IO流

.1 IO

输入(Input)指的是:可以让程序从外部系统获得数据(核心含义是“读”,读取外部数据)

输出(Output)指的是:程序输出数据给外部系统从而可以操作外部系统(核心含义是 “写”,将数据写出到外部系统)

.2 流

流是一个抽象、动态的概念,是一连串连续动态的数据集合

.3 Java中四大IO抽象类

InputStream/OutputStream 和 Reader/Writer 类是所有 IO 流类的抽象父类

.3.1 InputStream抽象类

InputStream 此抽象类是表示字节输入流的所有类的父类。InputSteam 是一个抽象类,它不可以实例 化。 数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类 。

继承自 InputSteam 的流都是用于向程序中输入数据,且数据的单位为字节(8 bit)。

常用方法:

int read()读取一个字节的数据,并将字节的值作为 int 类型返回(0-255 之间的一个值)。 如果未读出字节则返回-1(返回值为-1 表示读取结束)。

void close()关闭输入流对象,释放相关系统资源。 OutputStream 此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到 某个目的地。

.3.2 OutputStream抽象类

此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节并将这些字节发送到 某个目的地

常用方法:

void write(int n)向目的地中写入一个字节。

void close()关闭输出流对象,释放相关系统资源。

.3.3 Reader抽象类

Reader 用于读取的字符流抽象类,数据单位为字符

常用方法:

int read()读取一个字符的数据,并将字符的值作为 int 类型返回(0-65535 之间的一个 值,即 Unicode 值)。如果未读出字符则返回-1(返回值为-1 表示读取结束)。

void close() 关闭流对象,释放相关系统资源。

.3.4 Writer抽象类

Writer 用于输出的字符流抽象类,数据单位为字符。

常用方法:

void write(int n) 向输出流中写入一个字符。

void close() 关闭输出流对象,释放相关系统资源。

.4 Java 中流的概念细分

.4.1 按流的方向分类

输入流:数据流从数据源到程序(以 InputStream、Reader 结尾的流)

输出流:数据流从程序到目的地(以 OutPutStream、Writer 结尾的

.4.2 按处理的数据单元分类

字节流:以字节为单位获取数据,命名上以 Stream 结尾的流一般是字节流, 如 FileInputStream、FileOutputStream。

字符流:以字符为单位获取数据,命名上以 Reader/Writer 结尾的流一般是字 符流,如 FileReader、FileWrite

.4.3 按处理对象不同分类

节点流:可以直接从数据源或目的地读写数据,如 FileInputStream、FileReader、 DataInputStream 等。

处理流:不直接连接到数据源或目的地,是”处理流的流”。通过对其他流的处 理提高程序的性能,如 BufferedInputStream、BufferedReader 等。处理流也叫 包装流。

节点流处于 IO 操作的第一线,所有操作必须通过它们进行;处理流可以对节 点流进行包装,提高性能或提高程序的灵活性

.5 Java 中 IO 流类的体系

Java 为我们提供了多种多样的 IO 流,我们可以根据不同的功能及性能要求挑选合适的 IO 流

  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 进行包装,可以方便地输出字符,更加灵活。

.6 File类

.6.1 File 类的作用

File 类是 Java 提供的针对磁盘中的文件或目录转换对象的包装类。一个 File 对象而可以
代表一个文件或目录,File 对象可以实现获取文件和目录属性等功能,可以实现对文件和目
录的创建,删除等功能。

.6.2 File 类操作目录与文件的常用方法

.6.2.1 针对文件操作的方法

createNewFile()//创建新文件。
delete()//直接从磁盘上删除
exists()//查询磁盘中的文件是否存在

getAbsolutePath()//获取绝对路径
getPath()//获取相对路径
getName()//获取文件名 相当于调用了一个 toString 方法。
isFile()//判断是否是文件
length()//查看文件中的字节数
isHidden()//测试文件是否被这个抽象路径名是一个隐藏文件

.6.2.2 针对目录操作的方法

exists()//查询目录是否存在
isDirectory()//判断当前路径是否为目录
mkdir()//创建目录
getParentFile()//获取当前目录的父级目录。
list()//返回一个字符串数组,包含目录中的文件和目录的路径名。
listFiles//返回一个 File 数组,表示用此抽象路径名表示的目录中的文件。

.6.3 File 类的基本使用

.6.3.1 操作文件
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());
   }
}
.6.3.2 操作目录
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);
}S
ystem.out.println("-----------------------");
File[] arr2 = file2.listFiles();
for(File temp :arr2){
System.out.println(temp);
}
}
}

.6.4 常用流对象

.6.4.1 文件字节流

FileInputStream 通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文
本文件等)。Java 也提供了 FileReader 专门读取文本文件。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件。Java 也提供
了 FileWriter 专门写入文本文件。

.6.4.1.1 文件字节输入流
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();
}
}
}
}
.6.4.1.2 文件字节输出流
public class FileStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try{
//创建文件字节输入流对象
fis = new FileInputStream("d:/sxt.jpg");
//创建文件字节输出流对象
fos = new FileOutputStream("d:/aa.jpg");
int temp = 0;
while((temp = fis.read()) != -1){
fos.write(temp);
} /
/将数据从内存中写入到磁盘中。
fos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(fis != null){
fis.close();
} i
f(fos != null){
fos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
.6.4.1.3 通过缓冲区提高读写效率

方式一
通过创建一个指定长度的字节数组作为缓冲区,以此来提高 IO 流的读写效率。该方式
适用于读取较大图片时的缓冲区定义。注意:缓冲区的长度一定是 2 的整数幂。一般情况下
1024 长度较为合适。

方式二
通过创建一个字节数组作为缓冲区,数组长度是通过输入流对象的 available()返回当前
文件的预估长度来定义的。在读写文件时,是在一次读写操作中完成文件读写操作的。注意:
如果文件过大,那么对内存的占用也是比较大的。所以大文件不建议使用该方法。

.6.4.1.4 通过字节缓冲流提高读写效率

Java 缓冲流本身并不具有 IO 流的读取与写入功能,只是在别的流(节点流或其他处理
流)上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包
装流)

当对文件或者其他数据源进行频繁的读写操作时,效率比较低,这时如果使用缓冲流就
能够更高效的读写信息。因为缓冲流是先将数据缓存起来,然后当缓存区存满后或者手动刷
新时再一次性的读取到程序或写入目的地。
因此,缓冲流还是很重要的,我们在 IO 操作时记得加上缓冲流来提升性能。
BufferedInputStream 和 BufferedOutputStream 这两个流是缓冲字节流,通过内部缓存数
组来提高操作流的效率。

.6.4.1.5 定义文件拷贝工具类
.6.4.2 文件字符流
.6.4.2.1 文件字符输入流
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){20
frd.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
.6.4.2.2 文件字符输出流
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();
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();
} i
f(fw2 != null){
fw2.close();
}
}catch(Exception e){
e.printStackTrace();21
}
}
}
}
.6.4.2.3 使用字符流实现文本文件的拷贝处理
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);
}f
w.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(fr != null){
fr.close();
}i
f(fw != null){
fw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
.6.4.3 字符缓冲流

BufferedReader/BufferedWriter 增加了缓存机制,大大提高了读写文本文件的效率。

.6.4.3.1 字符输入缓冲流

BufferedReader 是针对字符输入流的缓冲流对象,提供了更方便的按行读取的方法:
adLine(); 在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。

.6.4.3.2 字符输出缓冲流

BufferedWriter 是针对字符输出流的缓冲流对象,在字符输出缓冲流中可以使用
newLine();方法实现换行处理。

.6.4.3.3 通过字符缓冲流实现文本文件的拷贝
.6.4.3.4 通过字符缓冲流为文件中的内容添加行号
.6.4.4 转换流

InputStreamReader/OutputStreamWriter 用来实现将字节流转化成字符流。比如,如下场
景:
System.in 是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必
须用到缓冲字符流 BufferedReader 特有的方法 readLine(),但是经过观察会发现在创建
BufferedReader 的 构 造 方 法 的 参 数 必 须 是 一 个 Reader 对 象 , 这 时 候 我 们 的 转 换 流
InputStreamReader 就派上用场了。
而 System.out 也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用到字符流的 write(String str)方法,所以我们
要使用 OutputStreamWriter 将字节流转化为字符流。

.6.4.5 字符输出流

在 Java 的 IO 流中专门提供了用于字符输出的流对象 PrintWriter。该对象具有自动行刷
新缓冲字符输出流,特点是可以按行写出字符串,并且可通过 println();方法实现自动换行

.6.4.6 字节数组流

ByteArrayInputStream 和 ByteArrayOutputStream 经常用在需要流和数组之间转化的情况

.6.4.7 数据流

数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式
从底层输入输出流中操作 Java 基本数据类型与字符串类型。
DataInputStream 和 DataOutputStream 提供了可以存取与机器无关的所有 Java 基础类型
数据(如:int、double、String 等)的方法。

.6.4.8 对象流
.6.4.8.1 对象的序列化和反序列化
.6.4.8.1.1 序列化和反序列化是什么

当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都
会以二进制序列的形式在网络上传送。比如,我们可以通过 http 协议发送字符串信息;我
们也可以在网络上直接发送 Java 对象。发送方需要把这个 Java 对象转换为字节序列,才能
在网络上传送;接收方则需要把字节序列再恢复为 Java 对象才能正常读取。
把 Java 对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为 Java 对象的
过程称为对象的反序列化。
对象序列化的作用有如下两种:
持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。

网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传
递。

.6.4.8.1.2 序列化涉及的类和接口

ObjectOutputStream 代表对象输出流,它的 writeObject(Object obj)方法可对参数指定的
obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。
ObjectInputStream 代表对象输入流,它的 readObject()方法从一个源输入流中读取字节
序列,再把它们反序列化为一个对象,并将其返回。
只有实现了 Serializable 接口的类的对象才能被序列化。Serializable 接口是一个空接口,
只起到标记作用。

.6.4.8.2 操作基本数据类型
.6.4.8.2.1 写出基本数据类型数据
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 {34
try{
if(oos != null){
oos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
.6.4.8.2.2 读取基本数据类型数据
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();
}
}
}
}
.6.4.8.3 操作对象
.6.4.8.3.1 将对象序列化到文件

ObjectOutputStream 可以将一个内存中的 Java 对象通过序列化的方式写入到磁盘的文
件中。被序列化的对象必须要实现 Serializable 序列化接口,否则会抛出异常。

.6.4.8.3.1.1 创建对象
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;
}
}
.6.4.8.3.1.2 序列化对象
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();
}
}
}
}
.6.4.8.3.1 将对象序列化到文件
public class ObjectInputStreamObjectTypeDemo {
public static void main(String[] args) {
ObjectInputStream ois = null;
try{37
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();
}
}
}
}
.6.4.9 随机访问流

RandomAccessFile 可以实现两个作用:
\1. 实现对一个文件做读和写的操作。
\2. 可以访问文件的任意位置。不像其他流只能按照先后顺序读取。
在开发某些客户端软件时,经常用到这个功能强大的可以”任意操作文件内容”的类。比
如,软件的使用次数和使用日期,可以通过本类访问文件中保存次数和日期的地方进行比对
和修改。 Java 很少开发客户端软件,所以在 Java 开发中这个类用的相对较少。
学习这个流我们需掌握三个核心方法:
\1. RandomAccessFile(String name, String mode) name 用来确定文件; mode 取
r(读)或 rw(可读写),通过 mode 可以确定流对文件的访问权限。
\2. seek(long a) 用来定位流对象读写文件的位置,a 确定读写位置距离文件开头的字节个数。
\3. getFilePointer() 获得流的当前读写位置。

.6.4.10 File 类在 IO 中的作用

当以文件作为数据源或目标时,除了可以使用字符串作为文件以及位置的指定以外,我
们也可以使用 File 类指定

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++;
}b
w.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}i
f(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}

6.4.5 Apache IO 包

JDK 中提供的文件操作相关的类,但是功能都非常基础,进行复杂操作时需要做大量编
程工作。实际开发中,往往需要你自己动手编写相关的代码,尤其在遍历目录文件时,经常
用到递归,非常繁琐。 Apache-commons 工具包中提供了 IOUtils/FileUtils,可以让我们非常
方便的对文件和目录进行操作。
Apache IOUtils 和 FileUtils 类库为我们提供了更加简单、功能更加强大的文件操作和 IO
流操作功能。

.6.4.5.1 FileUtils 的使用

FileUtils 类中常用方法:
打开 FileUtils 的 api 文档,我们抽出一些工作中比较常用的方法,进行总结和讲解。总
结如下:
cleanDirectory:清空目录,但不删除目录。
contentEquals:比较两个文件的内容是否相同。
copyDirectory:将一个目录内容拷贝到另一个目录。可以通过 FileFilter 过滤需要拷贝的
文件。
copyFile:将一个文件拷贝到一个新的地址。
copyFileToDirectory:将一个文件拷贝到某个目录下。
copyInputStreamToFile:将一个输入流中的内容拷贝到某个文件。
deleteDirectory:删除目录。
deleteQuietly:删除文件。
listFiles:列出指定目录下的所有文件。
openInputSteam:打开指定文件的输入流。
readFileToString:将文件内容作为字符串返回。
readLines:将文件内容按行返回到一个字符串数组中。
size:返回文件或目录的大小。
write:将字符串内容直接写到文件中。
writeByteArrayToFile:将字节数组内容写到文件中。
writeLines:将容器中的元素的 toString 方法返回的内容依次写入文件中。

.6.4.5.2 IOUtils 的使用

打开 IOUtils 的 api 文档,我们发现它的方法大部分都是重载的。所以,我们理解它的方
法并不是难事。因此,对于方法的用法总结如下:
45
buffer 方法:将传入的流进行包装,变成缓冲流。并可以通过参数指定缓冲大小。
closeQueitly 方法:关闭流。
contentEquals 方法:比较两个流中的内容是否一致。
copy 方法:将输入流中的内容拷贝到输出流中,并可以指定字符编码。
copyLarge 方法:将输入流中的内容拷贝到输出流中,适合大于 2G 内容的拷贝。
lineIterator 方法:返回可以迭代每一行内容的迭代器。
read 方法:将输入流中的部分内容读入到字节数组中。
readFully 方法:将输入流中的所有内容读入到字节数组中。
readLine 方法:读入输入流内容中的一行。
toBufferedInputStream,toBufferedReader:将输入转为带缓存的输入流。
toByteArray,toCharArray:将输入流的内容转为字节数组、字符数组。
toString:将输入流或数组中的内容转化为字符串。
write 方法:向流里面写入内容。
writeLine 方法:向流里面写入一行内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoodEnough_YQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值