I/O流
I/O介绍
- I/O 即输入(读)/输出(写)的意思,是Input与Output的简写,任何编程语言都支持的,I/O 是机器获取和交换信息的主要渠道。
- I/O 的性能成为一个瓶颈问题。所以 Java 在 I/O 上也一直在做持续的优化,如从 1.4 开始引入了 NIO,提升了 I/O 的性能。
- 流就是数据传输,将流抽象为各种类,方便更直观的进行数据操作(为数据源和目的地建立一个输送通道)
例如:java程序员看Java编程思想,然后将自己的想法记录到书上。这个过程中思想从书中到你脑子里就是读取,又叫输入(Read/input)。你将自己瞎想的记录到书上,这个记录的过程叫做输入(Write/Output)。
IO流分类
字符流
以字符为基本单位进行传输,纯文本优先考虑
/**
Reader和Writer 是绝大部分Reader和Writer结尾的实现类的父类,这两个的大部分方法都能在绝大部分地方使用
*/
/*
read() 读一个字符
read(char[] cbuf) 将字符读入数组。
read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
read(CharBuffer target) 尝试将字符读入指定的字符缓冲区。
*/
/*
Writer
write(char[] cbuf) 写入一个字符数组。
write(char[] cbuf, int off, int len) 写入字符数组的一部分。
write(String str) 写一个字符串
write(String str, int off, int len) 写一个字符串的一部分。
close() 关闭流,先刷新。
*/
Reader
以案例来说明基本代码:
//读取文件
public void in(){
//创建文件对象,准备要读取的文件(字符流中不能通过目录直接访问)
File file = new File("目录+文件");
//准备输入流(创建输入流可能出现异常,通过try catch 抛出异常)
try(Reader r = new FileReader(file); //创建一个提供基本读取方法的对象
BufferedReader br = new BufferedReader(read)//缓冲字符输入流。装饰类、为低级字符输入流提供缓冲功能、提高效率。并且这里不再继承FilterReader、而是直接继承Reader
){
//设置读取长度的初始值
String l = "";
//读取内容
while((l=br.readLine())!=null){//readLine() 读一行文字。
System.out.println(len);
}
//关闭资源
}catch(Exception e){
e.printStackTrace();
}
}
/*
*/
/*
若不使用BufferReader来进行读取,则需要自行准备读取内容的数组
当然更推荐使用BufferReader再准备读取的数组,这样运行效率更高
*/
//准备需要读取内容的数组
char[] c = new char[1024];
//设置读取长度初始值
int len = 0;
//读取
while ((len = read.r(c))!=-1) {//read(char[] cbuf) 将字符读入数组。
System.out.println(Arrays.toString(c));
}
Writer
以案例来说明基本代码:
public void out() {
Scanner in = new Scanner(System.in);
File file=new File("目录+文件");
try (Writer writ = new FileWriter(file);//新建写入的对象,能进行Writer的基本方法
BufferedWriter bw = new BufferedWriter(writ)
){
String c = "";
do {
System.out.println("请输入:");
String str = in.next();//写入数据
bw.write(str);//缓冲流输入
bw.newLine();//另起一行
System.out.println("是否继续?y继续");
c = in.next();
} while (c.equals("y"));
writ.flush();//清空缓存
} catch (IOException e) {
e.printStackTrace();
}
}
用字符流复制粘贴文件
@Test //复制粘贴
public void copy() {
Writer writ =null;
try(Reader reader = new FileReader("F:\\eclipse\\school\\TesFileIO\\Hello.txt");
//true表示将内容拼接到末尾;;;默认false 表示替换源内容
){
writ =new FileWriter("F:\\\\eclipse\\\\school\\\\TesFileIO\\\\Test.txt",true);
char[] c = new char[1024];
int len = 0;
while ((len=reader.read(c))!=-1) {
//将读取到的内容通过输出流输出到文件
writ.write(c,0,len);//输出的长度为读取内容长度,而非整个数组长度
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
writ.flush();//清空缓存
} catch (IOException e) {
e.printStackTrace();
}
}
}
还可以进一步使用BufferedReader和BufferedWtiter来进行进一步的优化
字节流
字节流以字节(8bit)为单位,用处更广
InputStream
public void in() {
//创建用来读取的对象(可以直接放入要读取的文件了,不需要和字符流一样需要放入File文件)
try(InputStream in = new FileInputStream("F:\\eclipse\\school\\TesFileIO\\Hello.txt")) {
int b=0;
while((b=in.read())!=-1) {//当没有可读取的数据时read()方法返回-1;
//当然也可以创建读取的数组空间(缓冲)如:reader方法一样
System.out.print((char)b);
}
} catch (Exception e) {
e.printStackTrace();
}
}
OutputSteam
public void outStream() {
try(OutputStream out = new FileOutputStream("F:\\eclipse\\school\\TesFileIO\\Hello.txt")) {
String Str = "sadsafdfxsrghsyhluihi163896426591";//随意输入
//将字符串转换为字节组输出
out.write(Str.getBytes());
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
用字节流复制粘贴文件
@Test
public void bufcopy() {
long start = System.currentTimeMillis();
try(BufferedInputStream bis= new BufferedInputStream(new FileInputStream("F:\\eclipse\\school\\zuoye\\java\\Alex Webb GYM.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("F:\\eclipse\\school\\zuoye\\java\\new\\j.jpg"))
) {
byte[] b =new byte[1024];
int val =0;
while((val = bis.read(b))!= -1) {
bos.write(b,0,val);
}
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end-start);
}
可以通过系统运行时间来分别测试不使用BufferedInputStream;使用Buffered但不定义读取的缓冲数组 和;使用Buffered并且定义读取缓冲的运行时间的长短。
File文件类
通过代码说明一些常用类
//创建文件
//1.创建文件对象(File.separator静态常量,是一个自适应的斜线)
File file = new File("F:\\eclipse\\school\\TesFileIO");
//2.判断文件对象的目录是否存在(最后的文件是否存在,且前面不能有错)
if(!file.exists()) {//若不存在则创建文件夹
file.mkdirs();
}
File newFile = new File(file,"tes.txt");//文件可以直接进行创建
boolean flag=newFile.createNewFile();//判断路径是否存在,需要抛出异常
//删除文件
//创建文件对象,获取文件夹
File file = new File("F:\\eclipse\\school\\TesFileIO\\tes.txt");
System.out.println(file.getName()); //得到文件或目录的名字
//getPath() 得到file的路径(相对路径)
//getAbsolutePath() 得到file的路径(绝对路径)
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
if(file.delete()) {//删除文件
System.out.println("删除成功");
}else {
System.out.println("文件不存在,删除失败...");
}
查找所有文件:
/*
查找所有文件
1.查询获取当前文件下的所有文件名与目录
1.1判断文件下不能没有文件
2.循环判断获取的文件数组
2.1判断文件是否为文件夹(判断)
2.11为文件夹就再进行重新进入循环判断(再调用自己的方法————递归)
2.2不是就加1的文件数
*/
@Test
public void fineFile() {
//或取到所有的盘符
// list() 返回该路径下文件或者文件夹的名字数组
// listFiles() 返回该路径下文件或者文件夹组成的File数组
// listRoots() 列出可用的文件系统根。(盘符 如C盘,D盘)
File[] roots = File.listRoots();
System.out.println(roots);
File d = roots[1];
//获取d盘下所有的文件和数量
long num = showFile(d);
System.out.println("D盘中所有文件的数量为:"+num);
}
private long showFile(File file) {
long num = 0;
//获取当前目录下的子目录或文件
File[] files=file.listFiles();//listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。
//判断数组是否为空
if(files!=null) {
//循环所有目录
for (File file2 : files) {
//判断file2是否为目录; isDirectory() 测试此抽象路径名表示的文件是否为目录。
if(file2.isDirectory()) {
//递归方法,自己调用自己查询当前文件夹的下级文件
num+= showFile(file2);
}else {
num++;
//增加数量并展示文件
//System.out.println(file2.getParent()+File.separator+file2.getName());
}
}
}
return 0;
}
还有一些常用的方法以下列举出来:
增删方法: | |
---|---|
File(String pathname): | 通过路径名创建一个新 File 实例 |
File(File parent, String child): | 根据父目录路径File实例和子目录或文件路径创建一个新 File 实例。 |
File(String parent, String child) : | 根据父目录路径和子目录或文件路径创建一个新 File 实例。 |
renameTo() | 改名 |
createNewFile() | 创建新文件,只能一层******* |
查找的方法: | |
---|---|
isDirectory() | 是否为文件夹******* |
isFile() | 是否为文件******** |
getParentFile() | 得到父类路径的新文件 |
其它方法: | |
---|---|
separator() | 代替文件或文件夹路径的斜线或反斜线,防止跨平台出现错误 |
length() | 返回文件的长度 |