IO流
一.流的概念和作用
流是一组有序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,;流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观额进行数据操作.
二.File类
File类是java.io
包中很重要的一个类;
Flie类的对象可以表示文件,还可以表示目录,在程序中一个Flie类对象可以代表一个文件或目录
File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
public static void main(String[] args) {
/*
File类的构造方法的3种方式
*/
/* File f = new File("E:/demo.txt");
String p = "E:\\";
File f1 = new File(p,"demo.txt");
File f2 = new File(p,"api");
File fp = new File("E:\\" );
File f3 = new File(fp,"demo.txt");
File f4 = new File(fp,"api");*/
//File f = new File("demo.txt");
File f = new File("E:\\demo.txt");//在创建File对象时,不检测文件是否存在
System.out.println(f.length());//获得文件内容长度,以字节为单位
System.out.println(f.getParent());
System.out.println(f.getName());
System.out.println(f.getAbsolutePath());//获得相对路径的文件绝对路径
System.out.println(f.exists());//判断文件是否存在
System.out.println(f.isDirectory());//判断是否是文件夹
System.out.println(f.isHidden());//判断文件是否为隐藏文件
System.out.println(f.isAbsolute());//判断路径是否为绝对路径
System.out.println(f.canWrite());
System.out.println(f.canRead());
System.out.println(f.canExecute());
System.out.println(f.getPath());
System.out.println(f.lastModified());
String ld = DateUtil.dateToString(f.lastModified(), "yyyy-MM-dd HH:mm:ss");
System.out.println(ld);
}
public static void main(String[] args) {
/*
createNewFile() 创建文件
如果已经存在,就不创建了,返回false
如果不存在,就创建 返回true
如果盘符/地址在计算机没有,直接抛出异常
*/
//File f = new File("E:/demo.txt");
/* try {
System.out.println(f.createNewFile());
} catch (IOException e) {
e.printStackTrace();
}*/
//System.out.println(f.delete());//删除文件,存在返回true,不存在返回false.
//File f = new File("E:/demo/demo");
//System.out.println(f.mkdir());//只能创建单级文件夹
//f.mkdirs();//可以创建多级文件夹
//f.delete();//删除文件夹,删除时,文件夹中必须为空.
File f = new File("E:\\api");
//获取指定目录下的所有子级的文件或目录,以字符串形式返回
/* String [] farray = f.list();
for (String arr : farray){
System.out.println(arr);
}*/
/* //添加过滤条件,筛选文件
String [] farray = f.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return StringUtil.subFileType(name).equalsIgnoreCase("chm");
}
});
for (String arr : farray){
System.out.println(arr);
}
*/
File[] fs = f.listFiles(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
return StringUtil.subFileType(name).equalsIgnoreCase("chm");
}
});
for (File ft : fs){
System.out.println(ft);
}
File f1 = new File("E:\\demo.txt");
File f2 = new File("E:\\demo1.txt");
f1.renameTo(f2);//重命名
}
三.IO流的分类
字符流和字节流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。
结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
Java流的图结构
三.Java IO流对象
1.字节流
首先,我们得知道InputStream
和OutputStream
是所有字节流的父类,是一个抽象类
1)FileInputStream
和FileOutputStream
从本地文件中读取数据
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class StreamDemo1 {
public static void main(String[] args) {
/*File f = new File("E:\\demo1.txt");
FileInputStream in1 = new FileInputStream(f);*/
try {
/*
创建FileInputStream对象,指定要输入(读)的文件,文件不存在,会抛出异常
*/
FileInputStream in = new FileInputStream("E:\\demo.txt");
int b = in.read();
System.out.println(b);
int b1 = in.read();
System.out.println(b1);
int b2 = in.read();
System.out.println(b2);
int b3 = in.read();
System.out.println(b3);
int b4 = in.read();
System.out.println(b4);
int b5 = in.read();
System.out.println(b5);
int b6 = in.read();
System.out.println(b6);
int b7 = in.read();
System.out.println(b7);
//read() 每read()一次,从输入流中读到一个字节 返回,文件内容全部读完后,返回-1.
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamDemo2 {
public static void main(String[] args) {
/*File f = new File("E:\\demo1.txt");
FileInputStream in1 = new FileInputStream(f);*/
FileInputStream in =null;
FileOutputStream out = null;
try {
/*
创建FileInputStream对象,指定要输入(读)的文件,文件不存在,会抛出异常
*/
in = new FileInputStream("E:\\demo.txt");
/*
创建FileOutputStream对象, 自动创建输出的目标文件
*/
out = new FileOutputStream("F:\\demo.txt");
int b = 0;//记录每次读到的字节值
while ((b = in.read())!=-1){
System.out.println(b);
out.write(b);//向指定的文件中输出字节
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally {
//关闭流对象,释放系统资源
try {
if(in!=null){
in.close();
}
if(out!=null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamDemo3 {
public static void main(String[] args) throws IOException {
/*
创建FileInputStream对象,指定要输入(读)的文件,文件不存在,会抛出异常
*/
FileInputStream in = new FileInputStream("E:\\demo.txt");
/*
创建FileOutputStream对象, 自动创建输出的目标文件
*/
FileOutputStream out = new FileOutputStream("F:\\demo.txt");
int b = 0;//记录每次读到的字节值
while ((b = in.read())!=-1){
out.write(b);//向指定的文件中输出字节
}
//关闭通道,释放资源
in.close();
out.close();
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
public class StreamDemo4 {
public static void main(String[] args) throws IOException {
/*
创建FileInputStream对象,指定要输入(读)的文件,文件不存在,会抛出异常
*/
FileInputStream in = new FileInputStream("E:\\demo.txt");
/*
创建FileOutputStream对象, 自动创建输出的目标文件
*/
FileOutputStream out = new FileOutputStream("F:\\demo.txt");
/*
int read() 每次从输入流中读取一个字节 返回字节值 读完返回-1
int read(byte[] b) 每次从输入流中读取一个byte数组长度个字节,返回数组中实际装入内容个数, 读完返回-1
*/
byte[] b =new byte[6];//存储读到的内容
int length = 0;
while((length=in.read(b))!=-1){
System.out.println(length);
out.write(b, 0,length);//向外写出一个byte数组个字节,从数组指定位置开始,写length个字节
}
//关闭通道,释放资源
in.close();
out.close();
}
}
2)FilterInputStresm
和FilterOutputStresm
ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。而DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。
(1)BufferedInputStream
和BufferedOutputStream
package day3;
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) throws IOException {
//创建输入节点流,直接负责对文件读写的
FileInputStream in = new FileInputStream("E:\\feige.exe");
//创建处理对象,内部有一个缓冲数组 默认为8192个字节
BufferedInputStream bin = new BufferedInputStream(in,2048);
FileOutputStream out = new FileOutputStream("F:\\feige.exe");
BufferedOutputStream bout = new BufferedOutputStream(out,2048);
/* int b = 0;
while((b=bin.read())!=-1){
bout.write(b);
}*/
byte [] b = new byte[1024];
int length = 0;
while((length=bin.read(b))!=-1){
bout.write(b, 0, length);
}
bout.flush();//刷新缓冲区
bout.close();
bin.close();
}
}
(2)DataIntputStream
和DataOutputStream
数据读取
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class DataOutputStreamDemo{
public static void main(String[] args) throws IOException{
File file = new File("d:" + File.separator +"hello.txt");
DataInputStream input = new DataInputStream(new FileInputStream(file));
char[] ch = new char[10];
int count = 0;
char temp;
while((temp = input.readChar()) != 'C'){
ch[count++] = temp;
}
System.out.println(ch);
}
}
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamDemo{
public static void main(String[] args) throws IOException{
File file = new File("d:" + File.separator +"hello.txt");
char[] ch = { 'A', 'B', 'C' };
DataOutputStream out = null;
out = new DataOutputStream(new FileOutputStream(file));
for(char temp : ch){
out.writeChar(temp);
}
out.close();
}
}
3)ObjectInputStream
和ObjectOutputStream
对象输入输出流(装饰流)
package day4;
import java.io.*;
import java.util.Date;
/*
对象序列化 使用Serializable接口(接口中没有方法) 一个类实现Serializable接口,
就可以序列化
*/
public class ObjectStreamDemo implements Serializable {
/*
对象输入输出字节流
对象:内存中的对象
为什么将对象输出?
内存中的数据电脑关闭,服务器停止数据就会消失
有时候,需要将这些数据保存起来(这个过程被称为 对象序列化)
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化
/* FileOutputStream out=new FileOutputStream("G:\\data.txt");
ObjectOutputStream oout=new ObjectOutputStream(out);
String s="abc";
Date date=new Date();
oout.writeObject(s);
oout.writeObject(date);
oout.close();*/
//反序列化
FileInputStream in=new FileInputStream("G:\\data.txt");
ObjectInputStream oin=new ObjectInputStream(in);
String s=(String) oin.readObject();
Date date=(Date) oin.readObject();
oin.close();
}
}
4)ByteArrayInputStream
和ByteArrayOutputStream
从Byte数组中读取文件
例:使用内存操作流将一个大写字母转化为小写字母
/**
* 使用内存操作流将一个大写字母转化为小写字母
* */
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String str="ROLLENHOLT";
ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream output=new ByteArrayOutputStream();
int temp=0;
while((temp=input.read())!=-1){
char ch=(char)temp;
output.write(Character.toLowerCase(ch));
}
String outStr=output.toString();
input.close();
output.close();
System.out.println(outStr);
}
}
5)几个特殊的输入流分析
LineNumberInputStream
主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream
,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。
PushbackInputStream
其功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。
StringBufferInputStream
已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String 应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。
SequenceInputStream
可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。
2.字符流
Reader 是所有的输入字符流的父类,它是一个抽象类。
Writer 是所有的输出字符流的父类,它是一个抽象类。
1)InputStreamReader
和OutputStreamWriter
InputStreamReader
是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader
可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream
转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream
中的类使用一致。
OutputStreamWriter
是OutputStream
到Writer 转换的桥梁,它的子类FileWriter
其实就是一个实现此功能的具体类(具体可以研究一SourceCode
)。功能和使用和OutputStream
极其类似,
转换流的特点:
(1)其是字符流和字节流之间的桥梁
(2)可对读取到的字节数据经过指定编码转换成字符
(3)可对读取到的字符数据经过指定编码转换成字节
何时使用转换流?
当字节和字符之间有转换动作时;
流操作的数据需要编码或解码时。
具体的对象体现:
InputStreamReader:字节到字符的桥梁
OutputStreamWriter:字符到字节的桥梁
这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。
(1)将字节输出流转化为字符输出流
/**
* 将字节输出流转化为字符输出流
* */
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Writer out=new OutputStreamWriter(new FileOutputStream(file));
out.write("hello");
out.close();
}
}
(2)将字节输入流转换为字符输入流
/**
* 将字节输入流变为字符输入流
* */
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Reader read=new InputStreamReader(new FileInputStream(file));
char[] b=new char[100];
int len=read.read(b);
System.out.println(new String(b,0,len));
read.close();
}
}
2)BufferedReader
和BufferedWriter
BufferedReader
很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
BufferedWriter
是一个装饰器为Writer 提供缓冲功能。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 使用缓冲区从键盘上读入内容
* */
public class BufferedReaderDemo{
public static void main(String[] args){
BufferedReader buf = new BufferedReader(
newInputStreamReader(System.in));
String str = null;
System.out.println("请输入内容");
try{
str = buf.readLine();
}catch(IOException e){
e.printStackTrace();
}
System.out.println("你输入的内容是:" + str);
}
}
3)其他的一些字符流
(1)CharReader
、StringReader
是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader
是从与其它线程共用的管道中读取数据。
(2)FilterReader
是所有自定义具体装饰流的父类,其子类PushbackReader
对Reader 对象进行装饰,会增加一个行号。
(3)CharArrayWriter
、StringWriter
是两种基本的介质流,它们分别向Char 数组、String 中写入数据。
(4)PipedWriter
是向与其它线程共用的管道中写入数据,
(5)PrintWriter
和PrintStream
极其类似,功能和使用也非常相似。
四.对象序列化
对象序列化就是把一个对象变为二进制数据流的一种方法。
一个类要想被序列化,就行必须实现java.io.Serializable
接口。虽然这个接口中没有任何方法,就如同之前的cloneable
接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。
package day4;
import java.io.*;
import java.util.Date;
/*
对象序列化 使用Serializable接口(接口中没有方法) 一个类实现Serializable接口,
就可以序列化
*/
public class ObjectStreamDemo implements Serializable {
/*
对象输入输出字节流
对象:内存中的对象
为什么将对象输出?
内存中的数据电脑关闭,服务器停止数据就会消失
有时候,需要将这些数据保存起来(这个过程被称为 对象序列化)
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化
/* FileOutputStream out=new FileOutputStream("G:\\data.txt");
ObjectOutputStream oout=new ObjectOutputStream(out);
String s="abc";
Date date=new Date();
oout.writeObject(s);
oout.writeObject(date);
oout.close();*/
//反序列化
FileInputStream in=new FileInputStream("G:\\data.txt");
ObjectInputStream oin=new ObjectInputStream(in);
String s=(String) oin.readObject();
Date date=(Date) oin.readObject();
oin.close();
}
}
package day4;
import java.io.Serializable;
/*
需要被序列化类的对象,此类必须显示Serializable接口
实现此接口后,此类默认生出一个序列化id号,当此类内容发生修改后,这个id会会发生改变
也可以使用工具生成一个序列化id号,这样类如果发生修改,此类id依然不变
*/
public class Studnet implements Serializable {
private static final long serialVersionUID = 930203241074318639L;
int num;
/*
被transient关键字修饰的属性 可以不被序列化
*/
transient String name;
//String address;
public Studnet(int num, String name) {
this.num = num;
this.name = name;
}
@Override
public String toString() {
return "Studnet{" +
"学号=" + num +
", 姓名='" + name + '\'' +
/*"地址=" + address +*/'}';
}
}
package day4;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectStreamDemo2 {
public static void main(String[] args) throws IOException {
FileOutputStream out=new FileOutputStream("G:\\data.txt");
ObjectOutputStream oout=new ObjectOutputStream(out);
Studnet studnet=new Studnet(100,"zxc");
oout.writeObject(studnet);
oout.close();
}
}
package day4;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectStreamDemo3 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream in=new FileInputStream("G:\\data.txt");
ObjectInputStream oin=new ObjectInputStream(in);
Studnet studnet=(Studnet)oin.readObject();
System.out.println(studnet);
oin.close();
}
}
创作不易,大佬们留步… 动起可爱的双手,来个赞再走呗 (๑◕ܫ←๑)