2 Java流被分为 字节流和字符流两大流类,有什么区别 ?
字节流的两个基类是 inputstream 和outputstream,字符流的两个基类是 Reader和writer,他们都是Object类的直接子类,字符流是处理以8位字节为基本单位的字节流类,Reader和writer是专门处理16位字节的字符流类
- 字符流:因为数据有不同的编码,可以对字符进行不同的操作,其本质还是基于字节流,然后再查询相应的码表。一般用于处理纯文本数据。
- 字节流:可以处理所有类型数据,二进制文件(图片,音频等)。
- 输入流:读入数据,也就是数据的源,如键盘,磁盘文件,网络文件,内存等。字符流对应的基本输入流为Reader,字节流对应的基本输入流为InputStream。
- 输出流:输出数据,数据的目的地,如控制台,磁盘文件,内存等。字符流对应的基本输出流为Writer,字节流对应的基本输出流为OutputStream。
二、字符流
字符流的基本输入输出流是Reader和Writer,两者有一些常用的方法:
Reader的常用读取操作:
- int read() 读取单个字符。 还有一点关于数据的读入过程,如使用int read()一个字节一个字节的读入,到达流尾时,返回-1,这种方式,需要注意其返回int需要强制转换一下,如int data = reader.read();,那么读到的数据便是(char)data
- int read(char[] cbuf) 将字符读入数组。
- abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
Writer的常用写入操作:
- abstract void flush() 刷新该流的缓冲。
- void write(char[] cbuf) 写入字符数组。
- void write(int c) 写入单个字符。
- void write(String str) 写入字符串。
- void write(String str, int off, int len) 写入字符串的某一部分。
在使用Reader和Writer进行数据流的读入和写入操作时是不会直接创建Reader和Writer对象的,一般都是使用其子类,如FileReader和FileWriter,示例代码如下:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReaderDemo {
public static void main(String[] args) throws IOException {
//创建一个FileReader对象用来读取文件中的字符
FileReader reader=new FileReader("/Users/mac/frf");
int ch;
while( (ch=reader.read())!=-1) {
System.out.println((char)ch);
}
reader.close();
}
}
注意:io流在进行数据读写操作时会出现异常,然而一遇到io异常,io流的close()方法将无法得到执行,通常将关闭流的操作写在finally代码中
具体代码如下
finally {
try {
if (in!=null)
in.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if(out!=null)
out.close();
} catch ( Exception e) {
e.printStackTrace();
}
}
另一个例子:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[] args) {
FileReader reader=null;
FileWriter writer=null;
//向流中写入一个char[],内容为[i love you]
try {
writer =new FileWriter("file.txt");
writer.write("i love you".toCharArray());
writer.flush();
} catch (IOException e) {
//io异常在这里处理
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//在finally中关闭流,并判断是否为null
if (writer!=null) {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
try {
reader=new FileReader("file.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
char[] buf=new char[1024];
int n=0;
try {
while ((n=reader.read(buf))!=-1) {
System.out.println(new String(buf,0,n));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if (reader!=null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
BufferedWriter和BufferedReader使用简介
BufferedInputStream和BufferedOutputStream是为提高读取和写入的效率而出现的,当我们读取和写入数据时,可以现在内存中建立一个缓冲区,加快数据流的读写,其使用非常简单,将Reader或者Writer对象做为参数传递给其构造函数即可。功能和类似,示例代码如下:
import java.io.*;
public class TestBuffererWriter {
public static void main(String[] args) {
BufferedWriter bw=null;
BufferedReader br=null;
try {
bw=new BufferedWriter(new FileWriter("file.txt"));
bw.write("me,tpp".toCharArray());
bw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if (bw!=null) {
bw.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
try {
br=new BufferedReader(new FileReader("file.txt"));
String string;
while ((string=br.readLine())!=null) {
System.out.println(string);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
其中newLine()是输出一个换行,这种操作是跨平台的,即在Windows下输出\r\n,而在Linux下输出\n。
LineNumberReader使用简介
LineNumberReader单从类名上看,大致也知道了类的功能,便是可以输出文本文件的行号。这里行号是从1开始的,也可以使用setLineNumber(int)功能为其设置一个偏移值,如设置100,那么行号就会从101开始输出。
三、字节流
字符流操作的是纯文本内容,而字节流则是所有二进制文件都可以操作,如图片,视频,当然文件文件也是可以的。与字符流中读出和写入的类型为char型相对应,字节流读出和写入的是byte类型。字节流的两个基本输入输出流为InputStream和OutputStream,其功能与字符流的功能类似。对于文件的操作的流是相应的FileInputStream和FileOutputStream,下面通过一个图片拷贝功能作为字节流的一个示例代码:
import java.io.*;
class Demo {
public static void main(String[] args) throws IOException {FileInputStream fin = new FileInputStream("pic.png");
FileOutputStream fout = new FileOutputStream("pic2.png");// 与Reader不同的是这里使用的是byte类型
byte[] buf = new byte[1024];
int n = 0;while((n=fin.read(buf)) != -1) {
fout.write(buf, 0, n);
}// 关闭流
fin.close();
fout.close();
}
}BufferedInputStream和BufferedOutputStream使用简介
为了提高流操作的效率,这里也用相应的缓冲流,到底使用缓冲流与不使用缓冲流在效率上有多大的差别,可以通过比较得出结果。从下面代码的比较结果可以明显的发现,加入缓冲机制会大大提高程序的运行效率,原因大致解释为,未加入缓冲机制,每次读取read()都会调用系统底层读取磁盘操作,每次读取一个字节,非常耗时;而加入缓冲机制后,系统会一次将很多内容读取到内存,而调用read()时,只需要从内存中返回数据内容即可,大大减少了系统底层访问磁盘的次数,所以速度会加快很多。代码示例如下:
四、流的总结
Java将IO单独封装在一个包内,其中不同功能的流数不胜数,使用起来很容易混乱,所以,在使用java io流时需要按照一定的规则,如按照流的流向可以分为两大类,即输入流和输出流,输入流来自数据源,输出流有目的地。常见的源和目的地有如下:
- 源:键盘录入,磁盘读入,网络文件,内存。
- 目的地:控制台输出,磁盘文件,内存。
在明确流向后,在看流的数据是否为纯文本类型,若是则优先选用Reader或Writer字符流来操作,若是二进制类型,则使用InputStream和OutputStream字节流来操作。
提高流的效率,可以使用BufferedXXX来包装流。对于编码问题,可以使用InputStreamReader和OutputStreamWriter,其可以指定编码类型,如utf-8或者GBK等。
五、File的使用简介
是将文件和文件夹封装成的对象,方便对文件或者文件夹的属性信息进行操作,也可以作为参数传递。
File常用内容
static String separator为一种夸平台文件路径分隔符。
文件的创建和删除
File file = new File("file.txt");
file.createNewFile(); // 用于创建一个空文件,成功返回true,若已存在,则不会创建并返回false,
file.delete(); // 删除成功返回true,否则返回false
file.deleteOnExit(); // 退出时删除,一般用于系统退出时删除临时文件文件的判断
File file = new File("c:" + File.separator + "java", "info.txt");
file.canExecute(); // 是否可被执行
file.exists(); // 是否存在
file.mkdir(); // 创建目录,一层(成功返回true,失败返回false)
file.mkdirs(); // 创建多级目录
file.isDirectory(); // 是否为目录文件,不存在或者不是目录返回false
file.isFile(); // 是否为文件,不存在或不是文件返回false
file.isHidden(); // 是否为隐藏文件
file.isAbsolute(); // 是否为据对路径
file.getName(); // 获取文件名
file.getParh(); // 获取文件路径
file.getParent(); // 父目录
file.lastModified(); // 最后修改时间5、对象的序列化,实现Serializable接口,序列化即使将一个对象整个存储到文件中保存,可以实现数据的保存,下次可以将对象从文件中恢复出,只需要此对象实现了Serializable接口即可,注意的两点是,一是为对象添加static long serialVersionUID = 42L;随便指定一个数值,这是这个对象的唯一标识,即有相同标识才可以从文件中恢复出对象;二是在不需要序列化的对象前加上transient关键字。序列化只会序列化堆中的数据,静态数据不会被序列化,transient关键字的也不会。
import java.io.*;
public class TestPerson {
public static void main(String[] args) throws IOException {
Person p1=new Person("zhang", "2014", 20);
FileOutputStream fos=new FileOutputStream("we.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(p1);
}
}
class Person implements Serializable{
private String name;
private String id;
private int age;
public Person(String name, String id, int age) {
super();
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
小练习
编写一个程序分别使用一个字符流和字节流拷贝一个文本文件
import java.io.*;
public class Test01 {
public static void main(String[] args) throws Exception { // 字节流拷贝
FileInputStream in = new FileInputStream("E:/src.txt");
FileOutputStream out = new FileOutputStream("E:/des1.txt");
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
// 字符流拷贝
BufferedReader bf = new BufferedReader(new FileReader("E:/src.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("E:/des2.txt"));
String str;
while ((str = bf.readLine()) != null) {
bw.write(str);
bw.newLine();
}
bf.close();
bw.close();
}
}
java io流详解
最新推荐文章于 2021-06-02 16:45:31 发布