Java之IO流技术详解
何为IO?
首先,我们看看百度给出的解释。
I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分。
i是写入,Input的首字母。o是输出,Output的首字母。
IO 也称为IO流,IO = 流,它的核心就是对文件的操作,对于 字节 、字符类型的输入和输出流。
IO分类
IO流主要分为两大类,字节流和字符流。而按照作用分类,可以分为输入流和输出流。
流?
在电脑上的数据有三种存储方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,U盘等都是外存,在电脑上有内存条,缓存是在CPU里面的。外存的存储量最大,其次是内存,最后是缓存,但是外存的数据的读取最慢,其次是内存,缓存最快。这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的理解,我们可以简单的理解为容器,即外存是一个容器,内存又是另外一个容器。那又怎样把放在外存这个容器内的数据读取到内存这个容器以及怎么把内存这个容器里的数据存到外存中呢?
我们可以将这个整个看成一个水池。水池里面连接了出水口管与注水管。出水相当于我们的输出流。注水相当于我们的输入流。
File(文件类)
首先我们如果需要用IO流的话,我们肯定是需要创建一个我们所谓的**“水池”**的。
怎么创建呢?我们直接创建一个File类对象。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
//创建File对象
File file = new File("D:\\test.txt");
}
}
实际上这个对象,说白了就是用来储存一个IO流的文件地址的。
创建了对象后,它也没有任何什么操作,操作得使用这个对象调用方法。
我们先使用createNewFile()
方法创建我们上面那个路径的文件。
file.createNewFile();
注意定义文件路径时,可以用“/”或者“\”。
并且在创建一个文件时,如果目录下有同名文件将被覆盖。
因为有时候,可能我们的路径下已经存在了相对应的同名文件,所以我们要使用exists()
方法判断文件是否已经存在。
//创建File对象
File file = new File("D:\\test.txt");
//创建文件
try {
//判断文件是否存在
if(!file.exists()){
file.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
其实,File类里面还存在许多方法,用法都是可以直接调用的,作为一个合格的程序员,我们可以直接阅读相关说明而在合适的时候使用对应方法。
下面列举一些常用方法。
①、创建方法
1.boolean createNewFile() 不存在返回true 存在返回false 2.boolean mkdir() 创建目录,如果上一级目录不存在,则会创建失败 3.boolean mkdirs() 创建多级目录,如果上一级目录不存在也会自动创建
②、删除方法
1.boolean delete() 删除文件或目录,如果表示目录,则目录下必须为空才能删除 2.boolean deleteOnExit() 文件使用完成后删除
③、判断方法
1.boolean canExecute()判断文件是否可执行 2.boolean canRead()判断文件是否可读 3.boolean canWrite() 判断文件是否可写 4.boolean exists() 判断文件或目录是否存在 5.boolean isDirectory() 判断此路径是否为一个目录 6.boolean isFile() 判断是否为一个文件 7.boolean isHidden() 判断是否为隐藏文件 8.boolean isAbsolute()判断是否是绝对路径 文件不存在也能判断
④、获取方法
1.String getName() 获取此路径表示的文件或目录名称 2.String getPath() 将此路径名转换为路径名字符串 3.String getAbsolutePath() 返回此抽象路径名的绝对形式 4.String getParent()//如果没有父目录返回null 5.long lastModified()//获取最后一次修改的时间 6.long length() 返回由此抽象路径名表示的文件的长度。 7.boolean renameTo(File f) 重命名由此抽象路径名表示的文件。 8.File[] liseRoots()//获取机器盘符 9.String[] list() 返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。 10.String[] list(FilenameFilter filter) 返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。
字节流的使用
我们现在已经建好这个**“水池”了,同时还可以使用方法来获取到“水池”**的一些信息。
那接下来,我们可以试着创建一套流。
字节流,相当于一滴滴的水在一个管道里运输。这个管道我们可以抽象的称之为流。
我们还是先看看知乎上,某些大佬的解释。
大佬的解释
图中蓝色为主要对应部分,红色为不对应部分,黑色的虚线部分代表这些流一般需要搭配使用。从上面的图中可以看出Java IO中的字节流是非常对称的。我们来看看这些字节流中不对称的几个类。
LineNumberInputStream 主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。
PushbackInputStream 的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。
StringBufferInputStream 已经被Deprecated,本身就不应该出现在InputStream 部分,主要因为String 应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。
SequenceInputStream 可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。
PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例。
对于不完全学透的看法
听起来有些难度哈,这些高级用法我们先不管。我们先来看看它到底怎么用的。
那有人又说了,那如果不去学完整,以后要是不会用怎么办?
答:其实只需要掌握主要方法就可以,因为你如果需要实现一个非常用的东西,你肯定是事先就需要去查阅相关资料,而日常开发中,常用的也就可以信手拈来啦。
OutputStream(字节输出流)
这个抽象类是表示输出字节流的所有类的超类。
!!!这里的输出可不是我们正常的输出,它反而想法,是将字节写入到文件,可以理解为将字节输出到文件。
看看里面有些啥常用方法。
我们先演示一下,字节输出流如何使用?
//定义一个String值
String str = "Hello World";
等下我们利用字节流将这个String写入我们的文件里面。
等等!这里是字节流,我怎么可以直接写入**String
**?
嘿嘿,我们使用String类中的getBytes()方法将String转换成字节数组。
//将String值转换成字节数组
byte[] bytes = str.getBytes();
整个代码是这样的:
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
//创建File对象
File file = new File("D:\\test.txt");
//创建文件
try {
//判断文件是否存在
if(!file.exists()){
file.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
//定义一个String值
String str = "Hello World";
//创建字节流
FileOutputStream fos = null;
try {
//将File对象(即地址)给到FileInputStream
fos = new FileOutputStream(file);
//将String值转换成字节数组
byte[] bytes = str.getBytes();
//循环将字节数组写入到文件中
for (int i = 0; i < bytes.length; i++) {
//将bytes写入文件
fos.write(bytes[i]);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们进我们的文件看看输出效果。
就已经写入了我们的String里面的内容了。
InputStream(字节输入流)
这里我也就不解释了,他这个输入不是将内容输入到文件,而是将文件里面的内容输入到我们的代码中。
//创建字节输入流
FileInputStream fis = null;
try {
//将File对象(即地址)给到FileInputStream
fis = new FileInputStream(file);
//创建字节数组
byte[] bytes = new byte[1024];
//输出字节数组
int len = 0;
while ((len = fis.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
在上文,我们已经写入了一个Hello Word
我们现在这段代码,我们将会输出文件中的内容。
len = fis.read(bytes)) != -1
我现在还是先讲解一下这一段。
我们的
len
是定义的一个数值。而read()
方法,是为了读取到整个文件里面内容的字节长度,就像数组的lenth()
一样。而
!= -1
是因为,如果值为-1
那么,这个文件可以说是没有数据的,空的你也没必要输出。
而我们字节流呢,一般是用于读取二进制文件,如音频、图片这些,大片的文字内容还是交给字符流吧。
字符流的使用
上面的字节流,它是一个个的输出的,而我们现在的字符流,是大水管输出,一次可以运输一段。
一般可以用记事本打开的文件,我们可以看到内容不乱码的。就是文本文件,可以使用字符流。而操作二进制文件(比如图片、音频、视频)必须使用字节流。
FileWriter(字符输出流)
老规矩哈,方法自己看看。
先写入一个String
试试。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
String str = "嘿嘿!我是字符流·········";
//创建File对象
File file = new File("D:\\test.txt");
try {
//将str用writer写入文件
FileWriter fw = new FileWriter(file);
fw.write(str);
//关闭流,字符流必须关闭流才可以输出
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
写入效果如下:
实际上,写入字符串就几个步骤。
//1.将str用writer写入文件
FileWriter fw = new FileWriter(file);
//2.使用write()方法写入字符串
fw.write(str);
//3.关闭流,字符流必须关闭流才可以输出
fw.close();
FileReader(字符输出流)
//输出文件内容
try {
//创建输入字符流
FileReader fr = new FileReader(file);
//输出文件内容
int ch = 0;
while ((ch = fr.read()) != -1){
System.out.print((char)ch);
}
//关闭流
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
这里采用
Char
挨个字符遍历数据。
包装流
缓冲流
为什么使用缓冲流呢?
简单地说就是,写入数据更快,可以加速写入。
缓冲流,也叫高效流。 能够高效读写缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化对象等等。 它是四个基本File流的增强,所以也是4个流,按照数据类型分类。 缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO读取次数,从而提高读写的效率。
package IoDemo;
import java.io.*;
public class IoDemo {
public static void main(String[] args) {
//创建File对象
File file = new File("D:\\test.txt");
//创建缓冲流
BufferedWriter bw = null;
try {
//创建FileWriter对象
FileWriter fw = new FileWriter(file);
//创建BufferedWriter对象
bw = new BufferedWriter(fw);
//写入一首诗分四次写入
bw.write("窗前明月光,");
bw.write("疑是地上霜。");
bw.write("举头望明月,");
bw.write("低头思故乡。");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这个很简单,自己看就可以看懂。
转换流
InputStreamReader:把字节输入流转换为字符输入流
OutputStreamWriter:把字节输出流转换为字符输出流
我就不写示范了,网上找了一段。
//转换流实现将 a.txt 文件 复制到 b.txt 中
//1、创建源和目标
File srcFile = new File("io"+File.separator+"a.txt");
File descFile = new File("io"+File.separator+"b.txt");
//2、创建字节输入输出流对象
InputStream in = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(descFile);
//3、创建转换输入输出对象
Reader rd = new InputStreamReader(in);
Writer wt = new OutputStreamWriter(out);
//3、读取和写入操作
char[] buffer = new char[10];//创建一个容量为 10 的字符数组,存储已经读取的数据
int len = -1;//表示已经读取了多少个字符,如果是 -1,表示已经读取到文件的末尾
while((len=rd.read(buffer))!=-1){
wt.write(buffer, 0, len);
}
//4、关闭流资源
rd.close();
wt.close();
扩展
然后,找相关资料时,还涨了个知识。大家可以看看。
合并流
合并流:把多个输入流合并为一个流,也叫顺序流,因为在读取的时候是先读第一个,读完了在读下面一个流。
SequenceInputStream seinput = new SequenceInputStream();
new FileInputStream("io/1.txt"), new FileInputStream("io/2.txt"));
byte[] buffer = new byte[10];
int len = -1;
while((len=seinput.read(buffer))!=-1){
System.out.println(new String(buffer,0,len));
}
seinput.close();
这里先是创建了一个SequenceInputStream
对象,然后new
了两个FileInputStream
对象,我们使用合并流读取,先使用**seinput.read方法
**读取1.txt
的内容,然后再对其2.txt
的内容。
Java之IO流技术详解的更多相关文章
- Java 常用IO流操作详解
1.基本概念 IO:Java对数据的操作是通过流的方式,IO流用来处理设备之间的数据传输,上传文件和下载文件,Java用于操作流的对象都在IO包中. 2.IO流的分类 图示:(主要IO流) 3.字节流 ...
- Java中的IO流系统详解(转载)
摘要: Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java ...
- Java中的IO流系统详解
Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java 内用 U ...
- Java Garbage Collection基础详解------Java 垃圾回收机制技术详解
最近还是在找工作,在面试某移动互联网公司之前认为自己对Java的GC机制已经相当了解,其他面试官问的时候也不存在问题,直到那天该公司一个做搜索的面试官问了我GC的问题,具体就是:老年代使用的是哪中垃圾 ...
- IO流操作详解
注:FileReader继承InputStreamReader类,InputStreamReader实现Reader接口,其他同理. 对于文件内容的操作主要分为两大类 分别是: 字符流 字节流 其中, ...
- IO多路复用技术详解
IO多路复用:I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程.意思说一个或一组线程处理多个TCP连接.最大优势是减少系统开销小,不必创建过 ...
- Protocol Buffer技术详解(Java实例)
Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...
- Java基础-反射(reflect)技术详解
Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ...
- Java网络编程和NIO详解3:IO模型与Java网络编程模型
Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...
随机推荐
- MySQL JDBC常用知识,封装工具类,时区问题配置,SQL注入问题
JDBC JDBC介绍 Sun公司为了简化开发人员的(对数据库的统一)操作,提供了(Java操作数据库的)规范,俗称JDBC,这些规范的由具体由具体的厂商去做 对于开发人员来说,我们只需要掌握JDBC ...
- IO、NIO和AIO的区别
IO和NIO的区别:其本质就是阻塞和非阻塞的区别. 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,那么久一直等着,知道传输完毕为止.非阻塞概念:应用程序直接可以获取已经准备就绪好的 ...
- kafka客户端打印日志
kafka 0.10.0 java客户端使用slf4j作为日志门面,需要我们加入具体的日志实现依赖才能打印日志,日志框架:http://www.cnblogs.com/set-cookie/p/883 ...
- idea问题之"一个或多个listeners启动失败问题"
org.apache.catalina.core.StandardContext.startInternal 一个或多个listeners启动失败,更多详细信息查看对应的容器日志文件之 "A ...
- Java根路径设置(在获取本地路径时会获取到这个文件夹,,这样就可以专门放配置文件了)
在获取本地路径时会获取到这个文件夹,,这样就可以专门放配置文件了
- (stm32f103学习总结)—stm32外部中断
一.外部中断介绍 1.1 EXTI简介 EXTI简介 STM32F10x外部中断/事件控制器(EXTI)包含多达 20 个用于产生事 件/中断请求的边沿检测器.EXTI的每根输入线都可单独进行配置,以 ...
- c++中的左值和右值的理解
1.左值和右值的概念 C++中左值(lvalue)和右值(rvalue)是比较基础的概念,虽然平常几乎用不到,但C++11之后变得十分重要,它是理解 move/forward 等新语义的基础. 左值与 ...
- C# Coding Conventions, Coding Standards & Best Practices
C# Coding Conventions, Coding Standards & Best Practices Cui, Chikun Overview Introduction This ...
- 微信小程序版博客——开发汇总总结(附源码)
花了点时间陆陆续续,拼拼凑凑将我的小程序版博客搭建完了,这里做个简单的分享和总结. 整体效果 对于博客来说功能页面不是很多,且有些限制于后端服务(基于ghost博客提供的服务),相关样式可以参考截图或 ...
- h5 ios输入框与键盘 兼容性优化
起因 h5的输入框引起键盘导致体验不好,目前就算微信.知乎.百度等产品也没有很好的技术方案实现,尤其底部固定位置的输入框各种方案都用的前提下体验也并没有很好,这个问题也是老大难问题了.目前在准备一套与 ...