本章内容:
1.输入输出流
2.文件与目录管理File类
3.缓冲流
4.字节缓冲流
5.字符缓冲流
1.输入输出流
在前面的代码中,我们总是使用System.out.println()
来向屏幕输出一些内容。println是print line的缩写,表示输出并换行。因此,如果输出后不想换行,可以用System.out.print()
格式化输出:
如果要把数据显示成我们期望的格式,就需要使用格式化输出的功能。格式化输出使用System.out.printf()
,通过使用占位符%?
,printf()可以把后面的参数格式化成指定格式:
1 | public class Main{ |
占位符 | 说明 |
---|---|
%d | 格式化输出整数 |
%x | 格式化输出十六进制整数 |
%f | 格式化输出浮点数 |
%e | 格式化输出科学计数法表示的浮点数 |
%s | 格式化字符串 |
输入: 直接看案例
输入类型:
方法 描述
nextBoolean() 从用户输入中读取1个 boolean 值
nextByte() 从用户输入中读取1个 byte 值
nextDouble() 从用户输入中读取1个 double 值
nextFloat() 从用户输入中读取1个 float 值
nextInt() 从用户输入中读取1个 int 值
nextLine() 从用户输入中读取1个 String 值
nextLong() 从用户输入中读取1个 long 值
nextShort() 从用户输入中读取1个 short 值
1 | import java.util.Scanner; |
首先,我们通过import语句导入java.util.Scanner,import是导入某个类的语句,必须放到Java源代码的开头
然后,创建Scanner对象并传入System.in。System.out代表标准输出流,而System.in代表标准输入流。直接使用System.in读取用户输入虽然是可以的,但需要更复杂的代码,而通过Scanner就可以简化后续的代码。
有了Scanner对象后,要读取用户输入的字符串,使用scanner.nextLine()
;要读取用户输入的整数,使用scanner.nextInt()
。Scanner会自动转换数据类型,因此不必手动转换。
2.文件与目录管理
File类
Java的标准库java.io提供了File对象来操作文件和目录。我们从之前的知识可以推出java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作,并且类中存在构造函数,构造函数里传入的值为文件的路径。要构造一个file对象,需要传入文件路径:构造File对象时,可以是绝对路径(以根目录开头的完整路径),也可以是相对路径
创建File类对象
1 | File file = new File(path):path表示文件路径 |
注意Windows平台使用\作为路径分隔符,在Java字符串中需要用\\表示一个\。Linux平台使用/作为路径分隔符:
1 | linux: File f = new File("/usr/bin/javac"); |
File类的动态路径
- separator:获取当前系统的文件路径分隔符,windows系统为
\
,linux系统为”/“ - pathSeparator:获取当前系统的环境变量的路径分割符,在UNIX系统上字符为
:
, 而Windows系统上它是;
1 | // 操作路径:路径不能写死了(动态路径) |
File类的文件和目录操作方法
File对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。
- boolean isFile():判断File对象是否是文件
- boolean isDirectory():判断该File对象是否是已存在的目录
- boolean canRead():是否可读
- boolean canWrite():是否可写
- boolean canExecute():是否可执行
- long length():文件字节大小
- boolean exists(): 判断文件或目录是否存在
- createNewFile():当且仅当原文件不存在时才会创建一个新文件(需要处理IOException)
- mkdir():创建一个文件夹或者说目录
- mkdirs():既可以创建单级目录也可以创建多级目录,父目录不存在则会自动创建
- getAbsolutePath():返回此File的绝对路径名字符串
- getPath():获取文件完整路径
- getName():返回由此File表示的文件或目录的名称
- delete():删除该文件或目录(直接在硬盘上删除,不走回收站,无法找回,需要谨慎)
绝对路径与相对路径
- 绝对路径:是一个完整的路径
- 相对路径:相对路径指的是相对于当前项目的根目录
Java的相对路径读取文件方式:
- 在Java开发工具的project中使用相对路径
在project中,相对路径的根目录是project的根文件夹
创建文件的写法是:
1 | File f = new File("src/com/lavasoft/res/a.txt"); |
注意:路径不以“/”开头;脱离了IDE环境,这个写法就是错误的,也并非每个IDE都如此,但我见到的都是这样的。
- 通过CLASSPATH读取包内文件(推荐)
读取包内文件,使用的路径一定是相对的classpath路径,比如a,位于包内,此时可以创建读取a的字节流:
InputStream in = ReadFile.class.getResourceAsStream(“/com/lavasoft/res/a.txt”);
注意:这里必须以“/”开头;
通过IDEA开发工具运行代码时,文件路径结果没问题,但如果换成控制台执行,那么使用了项目相对路径的读取方式会失败,原因是,此时已经脱离了项目的开发环境(经测试,确实会在命令行无法使用)—–这个问题常常困扰着一些初学者,代码在开发工具好好的,发布后执行就失败了!
注意:
1.路径是不区分大小写
2.路径中的文件名称分隔符windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
注:java不同于Python,HTML引入文件时可以使用. :当前文件
或 .. :当前文件的上一级目录
,Java的相对路径是以当前的项目的根目录为准。
遍历文件和目录
File类遍历(文件夹)目录功能
- String[] list():返回一个String数组,表示该File目录中的所有子文件或目录(获取相对路径)
- File[] listFiles():返回一个File数组,表示该File目录中的所有的子文件或目录(获取绝对路径)
1 | public class Main { |
Path
Java标准库还提供了一个Path对象,它位于java.nio.file包。Path对象和File对象类似,但操作更加简单。如果需要对目录进行复杂的拼接、遍历等操作,使用Path对象更方便:
1 | public class Main { |
3.缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流:BufferedInputStream,BufferedOutputStream
- 字符缓冲流:BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
4.字节缓冲流
创建方式:
- BufferedInputStream(InputStream in):创建一个新的缓冲输入流
- BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流
1 | // 创建字节缓冲输入流 |
BufferedOutputStream
BufferedOutputStream表示字节缓冲输出流
- 继承自父类的共性成员方法:
- public void close():关闭此输出流并释放与此流相关联的任何系统资源。
- public void flush():刷新此输出流并强制任何缓冲的输出字节被写出。
- public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
- public void write(byte[] b, int off, int len):从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
- public abstract void write(int b):将指定的字节输出流。
- 构造方法
1 | BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流 |
- 使用步骤(重点)
- 创建FileOutputStream对象,构造方法中绑定要输出的目的地
- 创建BufferedOutputStream对象,构造方法中传递FileOutputStream对象对象,提高FileOutputStream对象效率
- 使用BufferedOutputStream对象中的方法write,把数据写入到内部缓冲区中
- 使用BufferedOutputStream对象中的方法flush,把内部缓冲区中的数据,刷新到文件中
- 释放资源(会先调用flush方法刷新数据,第4部可以省略)
BufferedInputStream
字节缓冲输入流
- 继承自父类的成员方法:
- int read()从输入流中读取数据的下一个字节
- int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
- void close() 关闭此输入流并释放与该流关联的所有系统资源
- 构造方法:
1 | BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 |
- 使用步骤(重点):
- 创建FileInputStream对象,构造方法中绑定要读取的数据源
- 创建BufferedInputStream对象,构造方法中传递FileInputStream对象,提高FileInputStream对象的读取效率
- 使用BufferedInputStream对象中的方法read,读取文件
- 释放资源
普通流与缓存流效率测试:
查询API,缓冲流读写方法与基本的流是一致的,我们通过复制大文件(400MB),测试它的效率
- 基本的io流,考虑到文件最好选择二进制的字节流来读写
1 | public class BufferedDemo { |
- 缓冲流,代码如下:
1 | public class BufferedDemo { |
- 如何更快呢?使用数组的方式
1 | public class BufferedDemo { |
5.字符缓冲流
BufferedWriter
字符缓冲输出流
继承自父类的共性成员方法:
- void write(int c) 写入单个字符
- void write(char[] ch)写入字符数组
- abstract void write(char[] ch, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数
- void write(String str)写入字符串
- void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
- void flush()刷新该流的缓冲
- void close() 关闭此流,但要先刷新它
构造方法:
1 | BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 |
- 使用步骤:
- 创建字符缓冲输出流对象,构造方法中传递字符输出流
- 调用字符缓冲输出流中的方法write,把数据写入到内存缓冲区中
- 调用字符缓冲输出流中的方法flush,把内存缓冲区中的数据,刷新到文件中
- 释放资源
1 | public class Demo03BufferedWriter { |
BufferedReader
字符缓冲输入流
继承自父类的共性成员方法:
- int read() 读取单个字符并返回
- int read(char[] ch)一次读取多个字符,将字符读入数组
- void close() 关闭该流并释放与之关联的所有资源
构造方法:
1 | BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 |
- 特有的成员方法:
String readLine() 读取一个文本行。读取一行数据,通过下列字符之一即可认为某行已终止:换行 (‘\n’)、回车 (‘\r’) 或回车后直接跟着换行(\r\n)。
返回包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
- 使用步骤:
- 创建字符缓冲输入流对象,构造方法中传递字符输入流
- 使用字符缓冲输入流对象中的方法read/readLine读取文本
- 释放资源
1 | public class Demo04BufferedReader { |