Java流的分类,一般可按以下方式分:
- 按方向分,分为输入流,输出流。
- 按类型分,分为字节流和字符流。
2.1字节流是通过字节来读取数据
2.2字符流是通过字符来读取数据 - 按操作方式分,分为节点流和过滤流。
3.1 可以直接创建的流称为节点流,比如输入流,输出流
3.2 过滤流可以装饰节点流,让流的功能变得更加强大,过滤流采用装饰者模式,对输入流进行包装。比如说BufferedInputStream,BufferedOutputStream,DataInputStream,DataOutputStream都是过滤流。 - 转换流。
废话不多说,看代码:
使用字节流读取文件内容:
public void test1(){
File file = new File("F:\hello.txt");
FileInputStream fis = null;
try {
//创建一个文件输入流
fis = new FileInputStream(file);
//创建一个字节数组用来存储读取的信息
byte[] buf = new byte[1024];
//len表示读取的长度
int len = 0;
//只要len大于-1说明读取到元素,可对元素直接进行操作
while((len=fis.read(buf))>-1){
//通过控制台输出程序,需要指明输出的长度
System.out.write(buf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if (fis!=null) {
//操作完成之后关闭流
fis.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如何通过操作字节流来实现简单的文件拷贝呢?使用未经包装的输入输出流来拷贝文件,看代码:
public void test2(){
long startTime = new Date().getTime();
File file = new File("F:\mysql-installer-community-5.6.22.0.msi");
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(file);
fos = new FileOutputStream("F:\1.msi");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
fos.write(buf, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis!=null) fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos!=null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
long endTime = new Date().getTime();
//查看效率
System.out.println((endTime-startTime)/1000);
}
最后的输出结果为2,也就是说拷贝一个接近300M的文件需要两秒钟。
再看看经过BufferedInputStream和BufferedOutputStream包装后的相同文件的拷贝,代码如下:
public void test3(){
long startTime = new Date().getTime();
File file = new File("F:\mysql-installer-community-5.6.22.0.msi");
FileInputStream fis = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream(file);
//将fis包装起来
bis = new BufferedInputStream(fis);
//将输出流包装
bos = new BufferedOutputStream(new FileOutputStream("F:\2.msi"));
byte[] buf = new byte[1024];
int len = 0;
while((len=bis.read(buf))!=-1){
bos.write(buf, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭流之后会自动flush
try {
if(bis!=null) bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bos!=null) bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
long endTime = new Date().getTime();
System.out.println((endTime-startTime)/1000);
}
这里的输出为0,也就是说相同的文件拷贝,包装后的流效率会大大提高,原先需要两秒才能完成的拷贝,现在1秒都不到。
再看DataInputStream和DataOutputStream,这两个依然是将InputStream流包装,包装完成之后可以用它写基本类型数据以及字符型数据。
public void test4(){
FileOutputStream fos = null;
DataOutputStream dos = null;
DataInputStream dis = null;
try {
fos = new FileOutputStream("F:\2.txt");
dos = new DataOutputStream(fos);
/**
* 每写一个Int类型数据,相当于写入四个字节数据,占四个字节,long是八个字节
* 依次类推
*/
dos.writeInt(1111);
dos.writeInt(2222);
dos.writeInt(3333);
dis = new DataInputStream(new FileInputStream("F:\2.txt"));
/**
* 每执行一次readInt(),相当于读取四个字节数据,读取其他数据依次类推
*/
System.out.println(dis.readInt());
System.out.println(dis.readInt());
System.out.println(dis.readInt());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(dos!=null) dos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(dis!=null) dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
再看看包装后的字符流输入与输出:
public void test5(){
BufferedReader br = null;
PrintWriter out = null;
try {
br = new BufferedReader(new FileReader("F:\hello.txt"));
out = new PrintWriter(new BufferedWriter(new FileWriter("F:\11.txt")));
String str = null;
while((str=br.readLine())!= null){
System.out.println(str);
out.println(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(br!=null) br.close();
} catch (IOException e) {
e.printStackTrace();
}
if(out!=null) out.close();
}
}
字节流和字符流之间的转换,可以使用
字符流 =InputStreamReader(字节流)
把从控制台输入的文本内容转存到文本当中:
public void test6() {
BufferedReader br = null;
PrintWriter out = null;
try {
br = new BufferedReader(new InputStreamReader(System.in));
out = new PrintWriter(new BufferedWriter(new FileWriter(
"F:\222.txt")));
String str = null;
while ((str = br.readLine()) != null) {
if (str.trim().equals("exit")) {
break;
}
System.out.println(str);
out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
if (out != null)
out.close();
}
}
把一个对象写入到文件中:
public void writeObject(){
User user = new User("zhangsan","123");
user.setMoney(200);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("F:\object.dat"));
oos.writeObject(user);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(oos!=null) oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
User.java
import java.io.Serializable;
public class User implements Serializable{
private String username;
private String password;
//添加了transient属性的字段不会被存储
private transient int money;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
从文件中读取一个对象:
public void readObject(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("F:\object.dat"));
User u = (User) ois.readObject();
System.out.println(u.getUsername()+","+u.getPassword()+","+u.getMoney());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出结果是:
由于给money字段添加了transient属性,所以money字段并不会被存储,当然也就读取不到。如果在User.java中删除transient,那么输出结果就是:
这个时候money就可被顺利的读取出来。