Java学习手册:Java IO,
Java学习手册:Java IO,
一、Java IO流的实现机制
在Java语言中,输入和输出都被称为抽象的流,流可以看作一组有序的字节集合,即数据在两设备之间的传输。
流的本质是数据传输,根据处理数据类型的不同,流可以分为两大类:字节流和字符流。
字节流以字节(8bit)为单位,包含两个抽象类:InputStream(输入流)和OutputStream(输出流)。
字符流以字符(16bit)为单位,根据码表映射字符,一次可以读多个字节,包含两个抽象类:Reader(输入流)和Writer(输出流)。
字节流和字符流最主要的区别为:字节流在在处理输入输出时不会用到缓存,而字符流用到了缓存。
二、Java中有几种类型的流?
答:常见的流有两种,分别为字节流和字符流。其中,字节流继承于InputStream与OutputStream,字符流继承于Reader与Writer。InputStream是所有字节输入流的父类,OutputStream是所有字节输出流的父类。Reader是字符输入流的父类,Writer是字符输出流的父类。在java.io包中还有许多其他的流,流的作用主要是为了改善程序性能并且使用方便。
注:InputStream和OutPutStream这两个类虽然提供了一系列和读写数据有关的方法,但是这两个类是抽象的,不能被实例化。
三、字节流与字符流
字节流可以处理所有类型的数据,如MP3、图片、文字、视频等。在读取时,读到一个字节就返回一个字节。在Java中对应的类以"stream"结尾。
字符流仅能够处理纯文本数据,如txt文本等。在读取时,读到一个或者多个字节,先查找指定的编码表,然后将查到的字符返回。在Java中对应的类都以"Reader"或"Writer"结尾。所有的字符流都是高级流。字符流是以字符(char)为单位读写数据的,一次处理一个unicode。字符流的底层仍然是基本的字节流。
实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时,使用了缓冲区在操作文件。字节流在在处理输入输出时不会用到缓存,而字符流用到了缓存。
字节输出流:程序→字节流(直接操作文件)→文件
字符输出流:程序→字符流→缓存→文件
四、文件流(字节流)
(1)FOS(FileOutputStream)
FileOutputStream是文件的字节输出流,使用该流以字节为单位将数据写入文件。
java.io.FileOutputStream向文件中写出字节的输出流,这是一个低级流,数据的去向明确(文件中)。
FileOutputStream(File file)//创建一个指向File对象表示的文件中写出数据的文件输出流
FileOutputStream(String filename)//创建一个向具有指定名称文件中写出数据的文件输出流
//注:若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
FileOutputStream(File file, boolean append)//创建一个向指定File对象表示的文件中写出数据的文件输出流
FileOutputStream(String filename, boolean append)//创建一个向具有指定名称的文件中写出数据的文件输出流
//注:以上两个构造方法中,第二个参数若为true,那么通过该FOS写出的数据都是在文件末尾追加的。
(2)FIS(FileInputStream)
FileInputStream是文件的字节输入流,使用该流可以以字节为单位,从文件中读取数据。
java.io.FileInoutStream从文件中读取数据的流,是一个低级流。
FileInputStream(File file)//创建一个从指定File对象表示的文件中读取数据的文件输人流
FileInputStream(String name)//创建用于读取给定的文件系统中的路径名name所指定的文件的文件输入流
int read()//从此输入流中读取一个数据字节,若返回-1则表示EOF(End od File)
void write(int d)//将指定字节写入此文件输出流,这里只写给定的int值的低八位
(3)文件复制
使用流的形式完成文件的复制操作。
①创建一个FileInputStream读取源文件
②创建一个FileOutputStream向目标文件写
③循环读取每一个字节并写入文件
④关闭两个流完成复制
五、缓冲流(字节流)
(1)BOS(BufferedOutputStream)
BufferedOutputStream缓冲输出流,内部维护着一个缓冲区,每当我们向该流写数据时,都会先将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。
①BOS实现写出缓冲
public void testBos() throws Exception{
FileOutputStream fos = new FileOutputStream("demo.txt");
//创建缓存字节输出流
BufferedOutputStream bos = new BufferedOutputStream(fos);
//所有字节被存入缓冲区,等待一次性写出
bos.write("helloworld".getBytes());
//关闭流之前,缓冲输出流会将缓冲区内容一次性写出
//数据在缓冲区中保存直到缓冲区满后才写出
bos.close();
}
②BOS的flush方法
void flush()//清空缓冲区,将缓冲区中的数据强制写出(一次性写出)。
//注:频繁使用该方法会提高写出次数从而降低写出效率
(2)BIS(BufferedInputStream)
BufferedInputStream是缓冲输入流。其内部维护着一个缓冲区(字节数组),使用该流在读写一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据被全部读取完毕,会再次读取若干字节从而反复,这样就减少了读取的次数,从而提高了读取效率。
BIS是一个处理流,该流为我们提供了缓冲功能。
①BIS实现输入缓冲
public void testBis() throws Exception{
FileInputStream fis = new FileInputStream("demo.txt");
//创建缓存字节输入流
BufferedInputStream bis = new BufferedInputStream(fis);
int d = -1;
//缓冲读入,实际上并非是一个字节一个字节从文件读取的
while((d=bis.read()) != -1) {
System.out.println(d+" ");
}
bis.close();//关闭流时只需关闭最外层的高级流即可
}
②缓冲流的方法 int read()
虽然也是返回一个字节,但实际上缓冲流会让其处理的流一次性读一组字节回来,并存入自身提供的字节数组(缓冲区),然后将第一个字节返回。这样的好处在于当我们再次调用该方法读取第二个字节时,缓冲流会直接将字节数组中的第二个字节返回,而不是再去读取。(也是通过提高了读取量,减少读取次数来提高读取效率)
(3)实现基于缓存区的文件复制
package com.haobi;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/*
* 实现基于缓存区的文件复制
*/
public class CppyFile {
public static void main(String[] args) throws Exception {
//读取源文件
FileInputStream fis = new FileInputStream("E:\\File_java\\IODemo\\demo.txt");
//创建缓存字节输入流
BufferedInputStream bis = new BufferedInputStream(fis);
//向目标文件写
FileOutputStream fos = new FileOutputStream("demo_copy.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int d = -1;
//缓冲读入,实际上并非是一个字节一个字节从文件读取的
while((d=bis.read()) != -1) {
bos.write(d);
}
bis.close();
System.out.println("复制完毕!");
bis.close();
bos.close();
}
}
//程序输出结果如下:
复制完毕!
六、对象流(字节流)
序列化:从数据结构转化为字节的过程
对象序列化:将Java中对象转换为字节的过程(对象→字节)
持久化:把内存上的数据写入磁盘中做长久保存的过程
(1)ObjectOutputStream
ObjectOutputStream是用来对对象进行序列化的输出流,可以将Java中的任何对象转化为一组字节后写出。
void writeObject(Object o)//将指定的对象转换为一组字节后写出
(2)ObjectInputStream
ObjectInputStream是用来对对象进行反序列化的输入流。
Object readObject()//该方法可以从流中读取字节(必须是oos将对象转换的一组字节)并转换为对应的对象
1、在反序列化时,会检测待反序列化的对象与该类定义的现有版本是否一致,若不一致,则会抛出异常,反序列化失败
2、若版本号没变,但是类定义发生了改变,那么采用兼容模式:
原来对象有的属性,现在还有的就还原;
原来对象有的属性,现在没的就忽略;
原来对象没有的属性,现在还有的则使用默认值;
例:
private static final long serialVersionUID = 1l;
//ObjectOutputStream在对对象进行序列化时有1个要求,就是需要序列化的的对象所属的类必须实现Serializable接口。
transient关键字,该关键字修饰的属性在序列化时其值将被忽略。
七、转换流(字符流)
(1)OutputStreamWriter(字符输出流)
//构造方法
OutputStreamWriter(OutputStream out)
//是将给定的输出流转换为字符输出流,通过该流写出的字符串是按照系统默认的字符集写出的。
//重载构造方法
OUtputStreamWriter(OutputStream out, String charsetName)
//该构造方法的第二个参数用来指定字符集,这样就可以按照当前指定的字符集将字符串转换为字节后写出。
(2)InputStreamReader(字符输入流)
转换过程:
(3)将osw.txt文件编码转换为GBK,并存入另一个文件中
package com.haobi;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/*
* 将osw.txt文件编码转换为GBK,并存入另一个文件中
* 思路:
* 由于osw.txt文件中的字符数据都是以UTF-8编码转换的字节保存的,所以我们要先用UTF-8编码
* 将每一个字符读取出来,然后再将该字符按照GBK编码写入另一个文件即可
*/
public class ChangeCharsetDemo {
public static void main(String[] args) throws IOException{
FileInputStream fis = new FileInputStream("osw.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");//若不写,则文件默认为GBK
FileOutputStream fos = new FileOutputStream("osw_copy.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
char[] buf = new char[100];
int len = -1;
while((len = isr.read(buf)) != -1) {
osw.write(buf, 0, len);
}
System.out.println("转码完成!");
osw.close();
isr.close();
}
}
//程序输出结果如下:
复制完毕!
八、缓冲字符流(字符流)
(1)PrintWriter
优势:1、读写字符快;2、可以以行为单位读写字符串;
缓冲字符输入输出流:BufferedReader、BufferedWriter
PrintWriter内部嵌套了BufferedWriter,所以其也具有缓冲功能,PrintWriter还提供了自动的行刷新功能。所以通常我们使用它来当作缓冲字符输出流。
//PrintWriter提供了很多构造方法,方便我们创建实例
//PrintWriter提供了用于流的嵌套(流的连接)使用的构造方法
PrintWriter(OutputStream out)
PrintWriter(Writer writer)
//若使用以流的方式创建PrintWriter,那么可以在构造方法中传入第二个参数,是一个Boolean值,该值若为true,
//则PrintWriter具有自动行刷新,意思是每当我们调用println方法写出内容后就会自动调用flush。如下:
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(Writer writer,boolean autoFlush)
//示例如下:
FileOutputStream fos = new FileOutputStream("pw.txt");
PrintWriter pw = new PrintWriter(fos, true);
(2)BufferedReader
BufferedReader是缓冲字符输入流,其内部提供了缓冲区,可以提高读取效率。
//常用构造方法
BufferedReader(Reader reader)
//可以按行读取字符串
String readLine()
//缓冲字符输出流的该方法可以按行为单位读取字符串,它会读取若干字符,直到读取了换行符为止,然后将换行符之前的所
//有字符组成一个字符串后返回,但是返回的字符串中不包含换行符。若返回null,则说明读取到末尾了,再没有数据可读。
(3)将当前程序的源文件读取出来并输出到控制台
package com.haobi;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/*
* 将当前程序的源文件读取出来并输出到控制台
*/
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException{
//字节流
FileInputStream fis = new FileInputStream("demo.txt");
//字节流→字符流
InputStreamReader isr = new InputStreamReader(fis);
//包装字符流(缓冲字符流只能包装字符流)
BufferedReader br = new BufferedReader(isr);
String line = null;
while((line = br.readLine())!= null) {//按行读取字符串
System.out.println(line);
}
br.close();
}
}
//程序输出结果如下:
demo
second
third
九、读取一个文件,把文件中的大写字母转换成小写字母,把小写字母转换成大写字母。
package com.haobi;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/*
* 把文件中的大写字母转换成小写字母,把小写字母转换成大写字母
*/
class MyOwnInputStream extends FilterInputStream{
public MyOwnInputStream(InputStream in) {
super(in);
}
public int read() throws IOException{
int c = 0;
if((c = super.read()) != -1) {
if(Character.isLowerCase((char)c)){//把小写转换为大写
return Character.toUpperCase((char)c);
}else if(Character.isUpperCase((char)c)){//把大写转换为小写
return Character.toLowerCase(c);
}else {//如果不是字母,保持不变
return c;
}
}else {
return -1;
}
}
}
public class InputStreamDemo {
public static void main(String[] args) {
int c;
try {
InputStream is = new MyOwnInputStream(new BufferedInputStream(new FileInputStream("iotest.txt")));
while((c = is.read()) >= 0) {
System.out.print((char)c);
}
is.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
相关文章
- 暂无相关文章
用户点评