JavaSE总结(三)IO流
一.File类
作用:文件和目录路径名的抽象表示。
二.IO原理
Java中的IO是阻塞式IO,是五种IO模型中的阻塞式IO模型,首先是用户线程发起IO请求,内核去查看数据是否就绪,如果数据没有就绪,用户线程就会一直等待着,移交出CPU.一旦数据就绪,数据会读到内核缓冲区,再从内核缓冲区拷贝到用户缓冲区。
三.流的分类
根据处理的数据类型不同可以分为字节流和字符流;
根据流的方向不同可以分为输入流和输出流
1.字节流和字符流:
1)字节流
InputStream(读取操作)、OutputStream(输出写操作)是java中按照最小字节单位读取的流,字节流是直接连接到数据源的流;
2)字符流
是一字符为单位进行数据处理的流,Reader,Write,本质上是基于字节流查找时去查找编码表
3)字节流和字符流的区别
1.处理的对象不同,字节流可以处理所有的数据类型的对象,而字符流只可以处理字符类型的对象;
2.读写的单位不同,字节流以字节为读写的单位(8位二进制),字符流以字符为单位(一次可能读写多个字节);
3.每次读取的大小不同:字节流一次读取8位二进制,字符流一次读取16位二进制;
结论:只要是纯文本数据优先使用字符流,除此之外都使用字节流。
2.输入流和输出流:
1)输入流(Input)
是指从数据源中进行读取操作,仅仅进行读操作;
2)输出流(Outpu)
是指将数据写到指定文件中;
结论:输入流和输出流都是针对文件,输入流就是去读文件中的数据源,输出流就是将数据写到指定文件。输入流:从文件读取数据到程序中;输出流:从程序将数据写到指定文件中
3.输入字节流(InputStream)与输出字节流(OutputStream)
InputStream:
1.InputStream是一个抽象类,是所有输入字节流的父类。
2.ByteArrayInputStream、StringBufferInputStream、FileInputStream是三中基本的介质流,他们分别从数组、StringBuffer、和本地文件中读取数据。
3.PipedInputStream是从与其它线程共用的管道中读取数据。
4.ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
===================================================================================================
OutputStream:
1.OutputStream 是所有的输出字节流的父类,它是一个抽象类。
2.ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
3.PipedOutputStream 是向与其它线程共用的管道中写入数据。
4.ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
4.输入字符流(Reader)和输出字符流(Write)
Reader:
1.BufferReader:输入缓冲流
2.InputStreamReader :转换流,实现了字符流和字节流之间的转换
3.FileReader:字符读取的文件流
Write:
1.WriteReader:输出缓冲流
2.OutputStreamReader:转换流,实现了字符流和字节流之间的转换
3.FileWrite:按字符写入的文件流
5.节点流和处理流
节点流:直接连接到数据源进行读写
- 父 类 :InputStream 、OutputStream、 Reader、 Writer
- 文 件 :FileInputStream 、 FileOutputStrean 、FileReader 、FileWriter 文件进行处理的节点流
- 数 组 :ByteArrayInputStream、 ByteArrayOutputStream、 CharArrayReader 、CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
- 字符串 :StringReader、 StringWriter 对字符串进行处理的节点流
- 管 道 :PipedInputStream 、PipedOutputStream 、PipedReader 、PipedWriter 对管道进行处理的节点流
处理流:在节点流的基础上再套一层
因为节点流处理数据不方便,所以才有了处理流,处理流要和节点流一起使用,在节点流的基础上再套一层,这就是处理流,处理流的构造函数总是要带一个其他流对象作为参数,一个流对象经过其他流的多次包装,称之为流的连接;
- 缓冲流:BufferedInputStrean 、BufferedOutputStream、 BufferedReader、 BufferedWriter 增加缓冲功能,避免频繁读写硬盘。
- 转换流:InputStreamReader 、OutputStreamReader实现字节流和字符流之间的转换。
- 数据流: DataInputStream 、DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来。
四.几个特殊的流
1.转换流
实现从字节流到字符流的转换
InputStreamReader 、OutputStreamWriter 要InputStream或OutputStream作为参数,实现从字节流到字符流的转换。
①InputStreamReader(InputStream); //通过构造函数初始化,使用的是本系统默认的编码表GBK。
②InputStreamReader(InputStream,String charSet); //通过该构造函数初始化,可以指定编码表。
③InputStreamReader(OutputStream); //通过该构造函数初始化,使用的是本系统默认的编码表GBK。
④OutputStreamwriter(OutputStream,String charSet); //通过该构造函数初始化,可以指定编码表。
2.对象流
序列化:将对象的信息存储到文件中的过程(ObjectOutputStream , writerObject(Object obj))
反序列化:将文件中的信息返回给类的对象的过程(ObjectInputStream,readObject())
//先写先读(第一次读的就是第一次写的)
注:如果要将某个类的对象进行序列化操作,必须对该类实现Serializable接口
transient和static修饰过的数据不能序列化,序列化和反序列化有一个相同的serialVersionUID才可以序列化成功,保证了数据的1一致性。
序列化:
public static void main(String[] args) {
//序列化
Persion p1=new Persion("张三", "男", 12);
Persion p2=new Persion("李四", "男", 22);
ObjectOutputStream os=null;
FileOutputStream fo=null;
try {
fo=new FileOutputStream("C:\\Users\\11295\\Desktop\\aa.txt");
os=new ObjectOutputStream(fo);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
os.writeObject(p1);
os.flush();
os.writeObject(p2);
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if (os!=null) {
try {
fo.close();
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
反序列化
//反序列化
ObjectInputStream os=null;
FileInputStream fs=null;
try {
fs=new FileInputStream("C:\\Users\\11295\\Desktop\\aa.txt");
os=new ObjectInputStream(fs);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Persion o1=(Persion)os.readObject();
Persion o2=(Persion)os.readObject();
System.out.println(o2+"====="+o1);
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (os!=null) {
try {
os.close();
fs.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
3.打印流(PrintStream )
- Syetem.out是它的一个对象;
- 文件不要求事先存在,要是文件存在且有内容,则会覆盖内容,要是文件不存在的话,则新创建文件将内容写进去。
PrintStream p=null;
try {
p=new PrintStream("C:\\Users\\11295\\Desktop\\aa.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p.print("周六的下午,阳光明媚,hhh");
if (p!=null) {
p.close();
}
4.随机访问流
(即可以作为输入流,也可以作为输出流)
RandomAccessFile 类的实例支持读取和写入随机访问文件
public class TestRandomAccessFile {
// 读取文件信息
@Test
public void test1() throws IOException {
// 读文件
RandomAccessFile raf = new RandomAccessFile("print.txt", "r");
// 类型Stream操作类似
byte[] bytes = new byte[20];
int len;
while ((len = raf.read(bytes)) != -1) {
String s = new String(bytes, 0, len);
System.out.println(s);
}
raf.close();
}
// 复制
@Test
public void test2() throws IOException {
// 读文件
RandomAccessFile raf = new RandomAccessFile("print.txt", "r");
// 写文件
RandomAccessFile rw = new RandomAccessFile("print1.txt", "rw");
// 类型Stream操作类似
byte[] bytes = new byte[20];
int len;
while ((len = raf.read(bytes)) != -1) {
rw.write(bytes, 0, len);
}
rw.close();
raf.close();
}
// 指定下标位置覆盖替换写入
@Test
public void test3() throws IOException {
// 写文件
RandomAccessFile rw = new RandomAccessFile("print1.txt", "rw");
rw.seek(2); // 从第三个位置写入 替换从此处的开始往后的内容
rw.write("AB".getBytes()); // 字符串转为字节数组
rw.close();
}
// 指定下标位置插入写入
@Test
public void test4() throws IOException {
// 写文件
RandomAccessFile rw = new RandomAccessFile("print1.txt", "rw");
rw.seek(2); // 从第三个位置写入
String lint = rw.readLine(); // 从当前光标开始位置一直到这一行结束
rw.seek(2); // 重新移动到插入点
rw.write("123".getBytes()); // 字符串转为字节数组
rw.write(lint.getBytes()); // 将插入前的内容拼接在后面
rw.close();
}
}
五.Java中标准输入输出流的重定向
一般来说System.in是键盘输入,System.out是输出到控制台,可以使用重定向,改变System.in和System.Out的输入输出位置;System类中提供了三个方法
static void setErr(PrintStream err)//错误输出流
Static void setIn(InputStream in)//输入流重定向
Static void setOut(PrintStream out)//输出流重定向
public class ReOut {
/**
* 重定向标准输出流
* 1.初始化PrintStream对象
* 2.调用System.setOut()方法,将标准输出流重定向到PrintStraem对象
* 3.操作System.out流
*/
public void testSetOut(String file) {
//1.创建输出流对象和打印流对象
PrintStream p1=null;
FileOutputStream fos=null;
try {
//2.根据文件地址初始化输出流
fos=new FileOutputStream(file);
//3.根据输出流初始化打印流
p1=new PrintStream(fos);
//4.使用System.setOut()方法将打印流重定向,定向到文件输出
System.setOut(p1);
//5.验证是否重定向成功
System.out.print("重定向成功!");
System.out.println(new ReOut());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if (p1!=null) {
p1.close();
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 重定向标准输入流
* 1.有一个已经初始化的输入流InputStream
* 2.调用System.setIn()方法,将标准输入流重定向到目的输入流
* 3.对System.in进行读取操作
* @throws IOException
*/
@Test
public void testSetIn() throws IOException {
//1.创建一个文件输入流对象
FileInputStream fis=null;
try {
//2.根据即将读取的文件的地址初始化输入流
fis=new FileInputStream("C:\\Users\\Administrator\\Desktop\\gg.txt");
//3.调用System.setIn()方法重定向输入流
System.setIn(fis);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line = br.readLine()) !=null){
System.out.println(line);
}
br.close();
fis.close();
}
}
更简单的方法
@Test
public void setOutInTest() throws FileNotFoundException {
//保留原始的输入输出流
InputStream in=System.in;
PrintStream out=System.out;
//将标准输入流重定向到in.txt
System.setIn(new DataInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\in.txt")));
Scanner input=new Scanner(System.in);
String str="";
//将标准输出流定义到out.txt
System.setOut(new PrintStream(new DataOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\out.txt"))));
while(input.hasNextLine()) {
str=input.nextLine();
System.out.println(str);
}
//将标准输入流定义到控制台
System.setIn(in);
//将标准输出流定义到控制台
System.setOut(out);
System.out.println("输入输出流已经恢复");
}