java - IO
前言
欢迎大佬荐临指导博主这一周的复习成果~~
什么是IO?它是这么分类的?它在java有哪些常用的类?它都有哪些具体的作用?那么就让我们围绕着几个问题来展开,希望大家可以通过这一篇博客认识IO,并且会简单的运用。
初识IO流
在学习IO的时候需要我们明白的几个基础的概念
文件与文件夹
我们都知道电脑中的东西都是已两种形式存在,一种是文件另外一种是文件夹的形式,如果我们需要找到它还需要一个路径
那么我们介绍几个基本的英语单词
- file:文件
是存储在某种长期储存设备或临时存储设备中的一段数据流
- directory:文件夹/目录
就是用来存放整理文件
- path:路径
路径在程序中的作用是操作对应的文件位置,所以我们在写路径时候的不能写死,以防出现错误
比如:
路径分隔符:在window中是分号,在linux中是冒号
名称分隔符:在window中是反斜杠\,在linux中是正斜杆/
下面看一个标准的路径写法的示例:读取的是c盘下的a.txt文件
IO流的原理及分类
什么是流呢?
在编程中每一门语言都有独特的操作文件的方式,而java就这种输入输出文件的方式称为流。
而流是指一串特定的数据,通过一个特定的通道流向指定的位置。
它可以用来处理传输文件、图片、音频、视频之类的数据,也可以处理传输经过编码成字节的字符串文件。
下面就是它的分类:
- 按照数据单位不同分为
- 字节流
- 输出流 - 数据的流向
- 输出
- 输入 - 按流的角色的不同分为
- 字节流
- 处理流/包装流
数据源
前面介绍了流的一些原理,那么我们把他比作一个水的传输过程,那么他就需要一个水箱,那么这个水箱就是数据源。
常见数据源有:数据库、磁盘文件、网络连接、IO设备。
字符和字节
先让我们看看百度百科中的定义
字符指类字形单位或符号,包括字母、数字、运算符号、标点符号和其他符号,以及一些功能性符号。
字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位。
这里我在简单的说一下我的理解,字符就是我们人可以看到的一个一个单位,即使用输入法可以单独打出来的内容。而对于中文英文而言就是一个一个单独的字符。而字节它是计算机的单位由于底层的0和1组成的。1字节 = 8位
绝对路径/相对路径
FIle类
我们学习一个类首先从它的构造方法看起
构造方法
File通过将给定路径字符串转化为抽象路径来创建一个新File实例。
-
构造方法一
File(String pathname)参数:
String pathname:字符串的路径名称
路径可以是以文件结尾,也可以是以文件夹结尾
路径可以是相对路径,也可以是绝对路径
通过将给定的路径名字转化为抽象类路径来创建新的File实例 -
构造方法二
File(String parent ,String child)
这个构造方法中参数可以传递两个一个父类的路径,一个子类的路径
那么这样写有什么好处呢?父路径和子路径可以动态的变化
-
构造方法三
FIle(File parent, String child)
父抽象路径名和子路径名字符串用以创建新的 File实例
file中的常用方法
这里就介绍几种常用的方法,详细介绍请到javaAPI中查看
获取功能的方法
-
file.getAbsolutePath( )
获取file中的路径(如果传入的是绝对路径就返回绝对路径,反之亦然) -
file.getPath( )
获取的构造方法中传递的路径 -
file.getName( )
获取文件传递路径的结尾部分 -
file.getLength( )
获取文件打小,但是不能获取文件夹的大小(如果传入的是文件夹的路径,那么最后返回0)
判断功能的方法
-
file.exists( )
这个功能使用的非常的频繁,它的主要作用就是用来判断传入的这个路径是否存在,返回一个布尔类型的字符 -
file.isFile( )
判断构造方法中传入的这个路径是否以该文件结尾 -
file.isDrectory( )
这个方法就是判断构造方法中传入的路径是否以文件夹的形式结尾,它与上面的方法互斥
创建删除的方法
- file.createNewFile( )
这个方法和它的名字一样,创建一个新的文件,这个也是一个很常用的方法
需要注意的是:这个方法会产生异常,需要处理(路径不存在就会产生异常) - file.mkdirs( )
这个方法是用来创建文件夹的,前面我们学习了mkdirs这个单词是文件夹的意思,那么这个加了s的意思就是创建多级的文件夹的意思,这个就算路径传入的不对也不会抛出异常,如果方法mkdirs没有加s意味着只能创建单级的文件夹 - file.delete( )
将构造函数中的指定的路径删除,下面两类不会删除
- 如果文件夹中有东西不会删除
- 路径不存在也不会删除
注意:删除在磁盘中直接删除,谨慎使用
在java中常用的方法
- 输入流(I)
- inputStream(字节输入流)
inputStrem字节输入流抽象类,他是所有类字节输入流的超类
下面我们用一段代码来介绍它的使用
@Test
public void fillIn() {
//定义文件路径
String insrc = "/Users/liudemac/Desktop/word/test.txt";
//初始化
FileInputStream fileInputStream = null;
try {
//定义数组接受这些内容
byte[] b = new byte[1024];
//这里定义整形数来获取遍历过程中的参数
int i;
fileInputStream = new FileInputStream(insrc);
//需要注意的是:如果他返回-1那么代表已经取出所有的字符
while ((i = fileInputStream.read(b)) != -1) {
//我们使用迭代器遍历得到最终的结果
for (byte b1 : b) {
System.out.print((char) b1);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//不要忘了最后的关闭资源
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e)
e.printStackTrace();
}
}
}
}
在使用中我已用代码详细的解释了字节输出流inputeStream的用法,还需要注意的是为了提高读的效率,read方法我传入的是一个数组。
InputStream读取流有三个方法,分别为read(),read(byte[] b),read(byte[] b, int off, int len)
- Reader(字符输出流)
用法与上字节输入流类似,这里我就不多赘述。
直接上代码
@Test
public void fillIn() {
String insrc = "/Users/liudemac/Desktop/word/test.txt";
FileReader fileReader = null;
try {
char[] b = new char[1024];
fileReader = new FileReader(insrc);
fileReader.read(b);
for (char b1 : b) {
System.out.print( b1);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 输出流(O)
- outputStream
这个与上边字节输入流相同
调用方法与上方一致,我这里就直接讲它的实现方法writer
@Test
public void fillOut() {
String outsrc = "/Users/liudemac/Desktop/word/test.txt";
FileOutputStream fileOutputStream = null;
try {
//注意这个ture,他代表的意思是是否覆盖之前写的,如果没有加这个就会将之前文件中的内容覆盖
fileOutputStream = new FileOutputStream(outsrc,true);
String str = "hello";
//括号中的第二第三参数表示从哪里开始,到哪里结束
fileOutputStream.write(str.getBytes(), 0, str.length());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
由节点流引出的包装流(Buffered)
节点流?
节点流比较好理解,就是咱们在上边java中常用的方法中举出的例子,它们通常只针对特定的数据源(上面已经解释)的读写资源。
即调用的各种抽象类的实现子类。
列如在上方我们调用的
节点流知道了,那什么是包装流呢?让我们看一段比较官方的解释
可以消除节点流的实现差异,也可以提供方便的的方法进行输入输出。
这句话听起来很迷糊,但是熟悉java特性的人就知道这是一种装饰器模式
修饰器模式
可以在不影响其他对象的前提下,以动态,透明的方法来获取对象
这种模式下创建了一个装饰类,用来包装原有的类,并在保持类方法完整性的前提下,提供了额外的功能。
需要注意的是,这个过程是通过调用包裹之后的对象完成功能添加的,而不是直接修改对象的行为,相当于添加了中间层。
那么包装流中的Buffer就是实现了子类中的方法,然后我们通过实现类去调用方法直接传入参数。
文件拷贝
最后让我们看一个IO的实际应用讲一个文件中的东西复制一份放到另外一个和文件中,简称拷贝。
有了前面的经验我相信小伙伴们一定能很快的写出来吧,我这里就放代码了
@Test
public void fileCopy() {
String insrc = "/Users/liudemac/Desktop/word/text.txt";
String putsrc = "/Users/liudemac/Desktop/word/text1.txt";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
byte[] b = new byte[1024];
int i;
fileOutputStream = new FileOutputStream(insrc);
fileInputStream = new FileInputStream(putsrc);
while ((i = fileInputStream.read(b)) != -1) {
//这个输出是用来将读取到的数据打印到控制台中,来看
System.out.printf(new String(b, 0, i));
fileOutputStream.write(b, 0, b.length);
}
} catch (
IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOutputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}