IO需要掌握的16个流
FileInputStream
FileOutputStream
FileReader
FileWriter
BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream
DataInputStream
DataOutputStream
ObjectInputStream
ObjectOutputStream
转换流(字节流转换成字符流)
InputStreamReader
OutputStreamWriter
PrintWriter
PrintStream(标准的输出流:默认输出到控制台)
FileInputStream
java.io.InputStream;
java.io.FileInputStream;文件字节数入流,按照字节方式读取文件
1.要读取某文件,先给这个文件创建一个"输入流"
//文件路径
String filePath = "txt";//相对路径,相对当前而言,在当前路径找下去;也可以是绝对路径,F:\\workspace\\08\\txt或者F:/workspace/08/txt
FileInputStream fis = new FileInputStream(filePath);
2.开始读(如果已经读取到文件的末尾,就会返回-1)
int temp=0;
while((temp=fis.read()) != -1){
System.out.println(temp);
}
3.释放资源,为了保证流一定会释放,所以在finally语句块中执行
finally{
fis.close();
}
注意:在读取文件时可能出现FileNotFountException,而该异常是编译期异常,因此要进行try…catch…处理
用上面这样的程序存在缺点:频繁访问磁盘,伤害磁盘,并且效率低,因此系统提供了int read(byte [] bytes);方法
该方法在读取之前在内存中准备一个byte数组,每次读取多个字节存储到bytes数组中一次读取多个字节,不是单个字节读取了,效率高
1.创建输入流
FileInputStream fis = new FileInputStream("txt");//txt.txt文件中存储的是abcd
2.开始读
//准备一个数组并声明一次最多可以读取几个字节
byte [] bytes = new byte[3];每一次最多读取3个字节
int i1 = fis.read(bytes);//3
//注意:int read(byte [] bytes);该方法返回的int类型的值代表的是:这次读取了多少个字节
//将byte数组转换成字符串
System.out.println(new String(bytes));//abc
int i2 = fis.read(bytes);//1
System.out.println(new String(bytes));//dbc
如果要想正确显示最后一次读取的数据,应该用String(byte [] bytes,int offset,int length);方法;其中offset是从几开始读,length是读取的长度
System.out.println(new String(bytes,0,i2));//dbc
3.关闭流资源
fis.close();
用数组的方式循环读取
FileInputStream fis = new FileInputStream("Test");
byte [] bytes = new byte[1024];//每次读取1KB
int temp = 0;
while((temp=fis.read(bytes)) != -1){
//将byte数组有效的数据转换成字符串
System.out.print(new String(bytes,0,temp));
}
fis.close();
注意:因为Test文件中本身自带换行,因此在输出时不能再用println()方法了,而要用print()方法
int available();返回流中剩余的估计字节数
skip(long n);从输入流中跳过并丢弃n个字节的数据
FileOutputStream
java.io.OutputStream;
java.io.FileOutputStream;文件字节输出流,将计算机内存中的数据写入硬盘文件中
FileOutputStream fos = null;
try{
//1.创建文件字节输出流
//fos = new FileOutputStream("temp01");//谨慎使用,会将源文件覆盖
//以追加的方式写入
fos = new FileOutputStream("temp01",true);
//2.开始写
String msg = "HelloWorld!";
//将String转换成byte数组
byte[] bytes = msg.getBytes();
fos.write(bytes);
//write(byte [] bytes,int offset, int length);该方法可以将数组中指定长度写入
//推荐最后的时候为了保证数据完全写入硬盘,所以要刷新
fos.flush();
}catch(Exception e){
e.printStream();
}finally{
//3.关闭流资源
if(fos != null){
try{
fos.close();
}catch(Exception e){
e.printStream();
}
}
}
关于文件复制粘贴
以下为了书写的简便不采用try…catch…进行处理,而是用throws语句进行声明,正常编程中要用try…catch…处理
//创建输入流
FileInputStream fis = new FileInputStream("FileOutputStream.java");
//创建输出流
FileOutputStream fos = new FileOutputStream("F:/FileOutputStream.java");
//一边读一边写
byte [] bytes = new byte[1024];
int temp = 0;
while(temp=fis.read(bytes) != -1){
//将byte数组中的内容直接写入
fos.write(bytes,0,temp);
}
//刷新
fos.flush();
//关闭流资源
fis.close();
fos.close();
FileReader
java.io.Reader;
java.io.InputStreamReader;//转换流(字节输入流-->字符输入流)
java.io.FileReader;文件字符输入流
//创建字符输入流
FileReader fr = null;
fr = new FileReader("Test");
//开始读
char [] chars = new char[512];//1KB,一个字符占两个字节
int temp = 0;
while((temp=fr.read(chars))!=-1){
//将char数组有效部分转换成字符串
System.out.print(new String(chars,0,temp));
}
//关闭
fr.close();
FileWriter
java.io.Writer;
java.io.OutputStreamWriter;//转换流(字节输出流-->字符输出流)
java.io.FileWriter;文件字符输出流
//创建字符输出流
//FileWriter fw = new FileWriter("temp02");//覆盖
FileWriter fw = new FileWriter("temp02",true);//追加
//开始写
fw.write("海波东--冰皇");
//将char数组的一部分写入
char [] chars = {'我','看','过','好','多','小','说','了','!'};
fw.write(chars,0,3);//我看过
//刷新
fw.flush();
fw.close();
用FileReader和FileWriter实现文件复制
只能复制纯文本
FileReader fr = new FileReader("Test02.java");
FileWriter fw = new FileWriter("F:/Test02.java");
char [] chars = new char[512];//1KB
int temp = 0;
while((temp=fr.read(chars))!=-1){
//写
fw.write(chars,0,temp);
}
fw.flush();
fr.close();
fw.close();
BufferedReader;带有缓冲区的字符输入流
BufferedWriter;带有缓冲区的字符输出流
BufferedInputStream;带有缓冲区的字节输入流
BufferedOutputStream;带有缓冲区的字节输出流
java.io.Reader;
java.io.BufferedReader;
//创建一个带有缓冲区的字符输入流
FileReader fr = new FileReader("BufferedReaderTest.java");//创建一个文件字符输入流
BufferedReader br = new BufferedReader(fr);//将文件字符输入流包装成带有缓冲区的字符输入流
//根据流出现的位置,流又可以分为:包装流和节点流,FileReader fr是一个节点流,BufferedReader br是一个包装流
//上面两句可以合为一句
BufferedReader br = new BufferedReader(new FileReader("BufferedReaderTest.java"));
//开始读
String temp = null;
while((temp=br.readLine())!=null){//br.readLine()方法读取一行,但是行尾不带换行符
System.out.println(temp);
}
//关闭流资源
//注意:关闭的时候只需要关闭最外层的包装流(这里有一个装饰者模式)
br.close();
如何将FileInputStream包装成BufferedReader?
//创建一个文件字符输入流
FileInputStream fis = new FileInputStream("BufferedReaderTest.java");
//转换流(将字节流转换成字符流)
InputStreamReader isr = new InputStreamReader(fis);//isr是字符流
//将字符流包装成带有缓冲区的字符流
BufferedReader br = new BufferedReader(isr);
//可以将上面的三句话合成一句
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("BufferedReaderTest.java")));
后面的代码和上面的一样,此处省略
接收用户键盘输入
以前的方式:采用Scanner 类;
Scanner s = new Scanner(System.in);//System.in是一个标准的输入流,默认接收键盘的输入
//程序执行到此处停下来,等待用户的输入
String str =s.next();
注意:该方式默认以空格作为分割,因此不能从键盘接收hello world!只能接收到hello
使用BufferedReader用来接收用户的输入
BufferedReader br = new BufferedReader(InputStreamReader(System.in));
//接受输入(每一次接收一行)
String str = br.readLine();
BufferedWriter
java.io.Writer;
java.io.BufferedWriter;
//创建带有缓冲区的字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("temp03"));
//开始写
bw.write("我现在不怎么看小说了,");
//写入一个行分隔符
bw.newLine();
bw.write("时间反而多了!");
//刷新
bw.flush();
//关闭
bw.close();
使用BufferedReader和BufferedWriter完成复制
//创建带有缓冲的字符输入流
BufferedReader br = new BufferedReader(new FileReader("Copy.java"));
//创建带有缓冲区的字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter(F:/Copy.java));
//边读边写
String temp = null;
while((temp=br.readLine())!=null){
bw.write(temp);
bw.readLine();//添加一个换行符,拷贝出来的文件会比源文件大2字节,一个换行符占2字节
}
//刷新
bw.flush();
//关闭
br.close();
bw.close();
DataOutputStream;数据字节输出流
可以将内存中的”int i=10;”写入到硬盘文件中,写进去的不是字符串,写进去的是二进制数据,带类型
java.io.OutputStream;
java.io.FileterOutputStream;
java.io.DataOutputStream;
//创建数据字节输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("temp04"));
//准备数据
byte b = 10;
short s = 11;
int i = 12;
long l = 1000L;
float f = 3.2f;
double d = 3.2;
boolean flag = true;
char c = 'a';
//写
dos.writeByte(b);
dos.writeShort(s);
dos.writeInt(i);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeBoolean(flag);
dos.writeChar(c);
//刷新dos.flush();
//关闭
dos.close();
注意:使用DataOutputStream写入的数据,只能用DataInputStream读取
DataInputStream
java.io.InputStream;
java.io.FilterInputStream;
java.io.DataInputStream;
//创建输入流
DataInputStream dis = new DataInputStream(new FileInputStream("temp04"));
//读
//注意:要使用该流读取数据,必须提前知道该文件中数据的存储格式、顺序且读的顺序必须和写入的顺序相同
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
boolean flag = dis.readBoolean();
char c = dis.readChar();
//下面接输出语句,不一一写了
System.out.print(b);
dis.close();
PrintStream;标准的输出流,默认打印到控制台,以字节方式
PrintWriter;以字符方式
PrintStream;
java.io.OutputStream;
java.io.FilterOutputStream;
java.io.PrintStream;
//默认是输出到控制台的
System.out.println("HelloWorld!");
//还可以写成下面这种形式
PrintStream ps = System.out;
ps.println("HelloWorle!");
//可以改变输出方向
System.setOut(new PrintStream(new FileOutputStream("log")));
//再次输出则打印到log,通常使用这种方式记录日志
System.out.println("hiahiahia...");
ObjectOutputStream;序列化JAVA对象到硬盘(Serial)
ObjectInputStream将硬盘中的数据”反序列化”到JVM内存中(DeSerial)
序列化
java.io.OutputStream;
java.io.ObjectOutputStream;
//创建java对象
User u = new User("张三","男","21");
//创建输出流(序列化流)(JVM中的java对象状态保存到硬盘中)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp05"));
//写
oos.writeObject(u);
//刷新
oos.flush();
//关闭
oos.close();
注意:User对象要想序列化,必须实现Serializable接口,而Serializable接口中有没有方法,像这样的接口,我们称为标识接口,标识接口的作用:起到标识作用,JVM如果看到该标识,会对它特殊待遇
反序列化
java.io.InputStream;
java.io.ObjectOnputStream;
//创建反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp05"));
//反序列化
Object o = ois.readObject();
//输出到控制台
System.out.println(o);//会调用User里重写的toString方法,结果为:[User:姓名:张三,性别:男,年龄:21]
//关闭
ois.close();
关于序列化版本号和transient关键字
因为User实现了Serializable接口,JVM会特殊待遇:会给该类添加一个属性
static final long serialVersionUID = 124941495L;
每次该类改动之后再次编译,系统都会给该类一个serialVersionUID,如果让系统自动生成,就会出现以前序列化的对象在反序列化的时候会报异常,那是因为系统每次为该类添加属性并赋值是不同的,因此在实际编程中,通常都是我们自己在需要序列化的类中写一个序列化版本号,另外,如果不想让该类中的某属性序列化,则在该属性的前面用关键字transient关键字修饰
java.io.File;
1.File类和流无关,不能通过该类完成文件的读写
2.File是文件和目录路径名的抽象表示形式
File代表的是硬盘上的Directory和file
File f1 = new File("Test01.java");//代表的是文件
File f2 = new File(D:/A/B/C);//代表的是目录
File f3 = new File(D:/TT);
System.out.println(f1.exists());//判断该文件是否存在
//如果不存在,创建该目录或文件
if(!f3.exists()){
f2.mkdir();//创建目录
f2.createNewFile();//创建文件
}
if(!f2.exists()){
f2.mkdirs();//创建多重目录
}
File中常用的方法
String getAbsolutePath();获取绝对路径
String getName();获取文件名
String getParent();获取父路径
boolean isDirectory();判断该文件是否是目录
boolean isFile();判断该文件是否是文件
long lastModified();获取文件最后一次修改的时间
long length();获取文件的长度(字节数)
File [] listFiles();//列出子文件并保存在数组里
如果要遍历数组里所有的以.java结尾的子文件,可以用增强for循环加判断条件
File f = new File(D:/workspace);
File [] fs = f.listFiles();
for(File f:fs){
if(f.getAbsolutePath().endsWith(.java)){
System.out.println(f.getAbsolutePath());
}
}
使用递归,找出某目录下的所有子目录以及子文件
import java.io.*;
public class Test{
public static void main(String [] args){
File f = new File("F:/workspace")
//调用方法完成查找
method(f);
}
public static void method(File f){
if(f.isFile()){
return;
}
File [] fs = f.listFiles();
for(File subF:fs){
System.out.println(subF.getAbsolutePath());
method(subF);
}
}
}