缓冲是缓冲到内存中。
(1)FileInputStream,FileOutputStream,FileReader,FileWriter是基于硬盘的,比较慢。
缓冲流是基于内存的,可以绕过硬盘的限制,快上好几万倍。
(2)为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组。
(3)根据数据操作单位可以把缓冲流分为:
BufferedInputStream 和 BufferedOutputStream
BufferedReader 和 BufferedWriter
(4)缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。
(5)对于输出的缓冲流,写出的数据会先在内存中缓冲,使用flush()将会使内存中的数据立刻写出。
输入流操作:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Test {
public static void main(String[] args) {
try {
Test.test("D:\\test2\\abc\\a\\b\\c\\tt.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test (String path) throws Exception{
FileInputStream fi = new FileInputStream(path);
BufferedInputStream br = new BufferedInputStream(fi);
byte[] b = new byte[10];
br.read(b);
br.close();
fi.close(); //先开的后关
System.out.println(new String(b));
}
}
输出流操作:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) {
try {
Test.test("D:\\test2\\abc\\a\\b\\c\\tt1.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test(String path) throws Exception{
FileOutputStream fo = new FileOutputStream(path);
BufferedOutputStream bo = new BufferedOutputStream(fo);
String s = "vicky";
bo.write(s.getBytes());
bo.flush();
fo.close();
bo.close();
}
}
利用缓冲字节流复制文件:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) {
Test.copy("D:\\test2\\tt2.txt","D:\\test2\\abc\\a\\tt.txt");
}
public static void copy (String from, String to) {
try {
FileInputStream fi = new FileInputStream(from);
FileOutputStream fo = new FileOutputStream(to);
BufferedInputStream bi = new BufferedInputStream(fi);
BufferedOutputStream bo = new BufferedOutputStream(fo);
byte[] b = new byte[10];
bi.read(b);
bo.write(b);
bo.flush();
bo.close();
bi.close();
fo.close();
fi.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
利用缓冲字符流复制文件:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
public class Test {
public static void main(String[] args) {
try {
Test.copy("D:\\test2\\abc\\a\\tt.txt","D:\\test2\\abc\\a\\b\\tt.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void copy (String from, String to) throws Exception{
BufferedReader br = new BufferedReader(new FileReader(from));
BufferedWriter bw = new BufferedWriter(new FileWriter(to));
char[] ch = new char[10];
br.read(ch);
bw.write(ch);
bw.flush();
br.close();
bw.close();
}
}
字节流和字符流基本操作一样。只是字节流用byte数组来接受流数据,而字符流用char数组来接受流数据。
并且由于字节流是基于二进制的,所以应用范围更广。
Buffered 和 File 基本形象上是一样的,只不过一个基于内存,一个基于硬盘。
编码格式:
所有文件都有编码模式。对于 txt 和 java 文件来说一般有三种编码方式:ISO8859-1、GBK和UTF-8。
第一种叫西欧编码,是纯英文编码,不适用于汉字。
后两种可以用于中文或英文。一般使用UTF-8编码。txt一般默认的是GBK。
转换流
转换字节输入流为字符输入流:
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) {
try {
Test.test();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test() throws Exception{
//字节流转换为字符流
FileInputStream fi = new FileInputStream("D:\\test2\\tt2.txt");
InputStreamReader in = new InputStreamReader(fi,"GBK"); //第一个参数是字节流,第二个参数是编码方式
//注意在转换字符流的时候,设置的字符集编码方式要与读取的文件的编码方式一致,否则会出现乱码
char[] c = new char[100];
int len = 0;
while ((len = in.read(c)) != -1) {
System.out.println(new String(c,0,len));
}
in.close();
fi.close();
}
}
转换字节输出流为字符输出流:
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class Test {
public static void main(String[] args) {
try {
Test.test();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test() throws Exception{
OutputStreamWriter sw = new OutputStreamWriter(new FileOutputStream("D:\\test2\\tt2.txt"),"GBK");
String s = "胡hu";
sw.write(s);
sw.flush();
sw.close();
}
}
需求:把控制台输入的内容写到指定的txt文件中,当接收到字符串“over”时就停止运行。
import java.io.*;
public class Test {
public static void main(String[] args) {
try {
Test.test("D:\\test2\\tt3.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test(String toPath) throws Exception{
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
BufferedWriter bw = new BufferedWriter(new FileWriter(toPath));
String line = "";
while ((line = br.readLine()) != null) {
if (line.equals("over"))
break;
//读取的每一行都写入txt文件中
bw.write(line);
}
bw.flush();
bw.close();
br.close();
is.close();
}
}
PrintStream:字节打印流
PrintWriter:字符打印流
专门用来做基本数据类型的读写。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) {
try {
Test.test("D:\\test2\\tt4.txt");
Test.test2("D:\\test2\\tt4.txt");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test (String path) throws Exception{
//数据输出流:DataOutputStream
//用数据输出流写到文件中的基本数据类型的数据是乱码,无法直接辨认,需要数据的输入流来读取
DataOutputStream out = new DataOutputStream(new FileOutputStream(path));
out.writeInt(100);
out.flush();
out.close();
}
public static void test2 (String path) throws Exception {
DataInputStream in = new DataInputStream(new FileInputStream(path));
System.out.println(in.readInt()); //用数据输入流读取数据输出流写到文件中的数据时,要保证使用和当时写的数据类型一致的类型来读取
//比如写的时候用out.writeInt(),那么读的时候就得用in.readInt()
in.close();
}
}
对象流主要是为了对象的持久化(存到硬盘) 和 对象的网络传输。
用于存储和读取对象的处理流。可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。涉及两个类:ObjectInputStream、ObjectOutputStream。
序列化(Serialize):
用 ObjectOutputStream 类将一个Java对象写入IO流中。
反序列化(Deserilize):
用 ObjectInputStream 类从IO流中回复Java对象。
ObjectOutputStream 类和 ObjectInputStream类不能序列化 static 和 transient 修饰的成员变量。即序列化和反序列化针对的是对象的属性而不适用于类的属性。
序列化是RMI(Remote Method Invoke,远程方法调用)过程的参数和返回值都必须实现的机制。
RMI是JavaEE的基础。因此序列化机制是JavaEE平台的基础。
如果需要让某个对象支持序列化机制,则必须让其类是可序列化的。而为了让某个类是可序列化的,该类必须实现 Serializable 和 Externalizable 两个接口之一。一般用 Serializable。
凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:private static final long serialVersionUID;
用来表明类的不同版本间的兼容性。
import java.io.*;
public class Test {
public static void main(String[] args) {
try {
Test.test2();
} catch (Exception e) {
e.printStackTrace();
}
}
//序列化测试
public static void test1() throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\test2\\tt5.txt"));
Person p = new Person();
p.name = "张三";
p.age = 18;
out.writeObject(p);
out.flush();
out.close();
}
//反序列化测试
public static void test2() throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\test2\\tt5.txt"));
Object o = in.readObject();
Person p = (Person) o;
in.close();
System.out.println(p.name);
System.out.println(p.age);
}
}
class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
}
注意:对象的序列化与反序列化使用的类要严格一致。包名、类名、类结构等所有内容都要一致。
RandomAccessFile类支持“随机访问”的方式。
“随机”是指程序可以直接跳到文件的任意地方来读、写文件。
RandomAccessFile 类对象包含一个记录指针,用以标示当前读写处的位置。
RandomAccessFile 类对象可以自由移动记录指针。
long getFilePointer()
:获取文件记录指针的当前位置。
void seek(long pos)
:将文件记录指针定位到 pos 位置。
import java.io.RandomAccessFile;
public class Test {
public static void main(String[] args) {
try {
Test.test2();
} catch (Exception e) {
e.printStackTrace();
}
}
//随机读文件
public static void test1() throws Exception{
//RandomAccessFile 的构造器有两个参数,参数1是读写文件的路径
//参数2是指定访问模式
//r:以只读方式打开
//rw:打开以便读取和写入
//rwd:打开以便读取和写入,同步文件内容的更新
//rws:打开以便读取和写入,同步文件内容和元数据的更新
RandomAccessFile ra = new RandomAccessFile("D:\\test2\\tt6.txt","r");
ra.seek(2); //设置读取文件内容的起始点
//注意换行符(两个字节)
//通过设置读取文件内容的起始点,来达到从文件的任意位置读取
byte[] b = new byte[100];
int len = 0;
while ((len = ra.read(b)) != -1) {
System.out.println(new String(b,0,len));
}
ra.close();
}
//随机写文件
public static void test2() throws Exception{
RandomAccessFile ra = new RandomAccessFile("D:\\test2\\tt7.txt","rw");
ra.seek(0); //在开头写
//ra.seek(ra.length()); //在结尾写
//注意:如果在文件开头或者中间的某个位置开始写的化,就会用写的内容覆盖掉等长度的原内容
String s = "hello";
ra.write(s.getBytes());
ra.close();
}
}