文件字符流
文件字节流可以处理所有的文件,如果处理文本文件,也可以使用文件字符流,它以字符为单位进行操作。
文件字符输入流
public static void main(String[] args) {
FileReader frd = null;
try{
//创建文件字符输入流对象
frd = new FileReader("E:/a.txt");
int temp = 0;
//一个一个读取
while((temp = frd.read()) != -1){
System.out.println((char)temp);
};
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(frd != null){
frd.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
文件字符输出流
public static void main(String[] args) {
FileWriter fw = null;
FileWriter fw1 = null;
try{
//创建文件字符输出流对象
fw = new FileWriter("E:/b.txt");
fw.write("精忠报国\r\n");
fw.write("yyds\r\n");
fw.flush();
//新的文件字符输出流对象会默认覆盖前者,通过append参数决定追加or覆盖
fw1 = new FileWriter("E:/b.txt",true);
fw1.write("noway\r\nyyds");
fw1.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (fw != null){
fw.close();
}
if (fw1 != null){
fw1.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
使用字符流实现文本文件的拷贝
public static void main(String[] args) {
FileReader frd = null;
FileWriter fw = null;
try{
frd = new FileReader("E:/a.txt");
fw = new FileWriter("E:/b.txt");
//不能使用available()
char[] buffer = new char[1024];
int temp = 0;
while((temp = frd.read(buffer)) != -1){
fw.write(buffer,0,temp);
}
fw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(frd != null){
frd.close();
}
if(fw != null){
fw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
字符缓冲流
BufferedReader/BufferedWriter增加了缓存机制,大大提高了读写文本文件的效率。
字符输入缓冲流
BufferedReader是针对字符输入流的缓冲流对象,提供了更方便的【按行读取】的方法:readLine();在使用字符流读取文本文件时,该方
法一行一读取。
public static void main(String[] args) {
FileReader fr = null;
BufferedReader br = null;
try{
fr = new FileReader("E:/a.txt");
br = new BufferedReader(fr);
//以行为单位读取
String temp = "";
while((temp = br.readLine()) != null){
System.out.println(temp);
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (br != null){
br.close();
}
if(fr != null){
fr.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
字符输出缓冲流
BufferedWriter是针对字符输出流的缓冲流对象,在字符输出缓冲流中可以使用newLine()方法实现换行处理。
public static void main(String[] args) {
FileWriter fw = null;
BufferedWriter bw = null;
try{
fw = new FileWriter("E:/b.txt");
bw = new BufferedWriter(fw);
bw.write("你好尚学堂");
bw.write("你好Oldlu");
//换行
bw.newLine();
bw.write("何以解忧");
bw.newLine();
bw.write("唯有杜康");
bw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(bw != null){
bw.close();
}
if(fw != null){
fw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
通过字符缓冲流实现文本文件的拷贝
/**
* 基于字符缓冲流实现文本文件的拷贝
*/
public static void copyFile(String source,String destination){
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new FileReader(source));
bw = new BufferedWriter(new FileWriter(destination));
String temp = "";
while((temp = br.readLine()) != null){
bw.write(temp);
bw.newLine();
}
bw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}
if(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
通过字符缓冲流为文件添加行号
/**
* 通过字符缓冲流实现文本文件的拷贝和添加行号
* 并不是每一行都有内容是如何实现拷贝的?
*/
public static void copyFileLineNum(String source,String destination){
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new FileReader(source));
bw = new BufferedWriter(new FileWriter(destination));
String temp = "";
int i = 1;
while((temp = br.readLine()) != null){
bw.write(i+"、"+temp);
bw.newLine();
i++;
}
bw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}
if(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
转换流
InputStreamReader/OutputStreamWriter用来实现将字节流转化成字符流。
比如,如下场景:
System.in是字节流对象,代表键盘的输入,如果我们想按行接收用户的输入时,就必须用到缓冲字符输入流BufferedReader特有的方法
readLine(),但是经过观察会发现在创建BufferedReader的构造方法的参数必须是一个Reader对象,这时候我们的lnputStreamReader
就派上用场了。
而System.out 也是字节流对象,代表输出到显示器,按行读取用户的输入后,并且要将读取的一行字符串直接显示到控制台,就需要用
到字符流的write(String str)方法,所以我们要使用OutputStreamWriter将字节流转化为字符流。
通过转换流实现键盘输入屏幕输出
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new InputStreamReader(System.in));
bw = new BufferedWriter(new OutputStreamWriter(System.out));
while(true){
bw.write("请输入:");
bw.flush();//如果不刷新,退出时还会显示一次请输入,并且第一次不会提示输入
String input = br.readLine();
if("exit".equals(input)){
break;
}
bw.write("您输入的是:"+input);
bw.newLine();
bw.flush();
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}
if(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
通过字节流读取文本文件并添加行号
/**
* 通过字节流读取文本文件并添加行号
*/
public static void copyFileStreamNum(String source,String destination){
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new InputStreamReader(new FileInputStream(source)));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destination)));
String temp = "";
int i = 1;
while((temp = br.readLine()) != null){
bw.write(i+"、"+temp);
bw.newLine();
i++;
}
bw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}
if(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
字符输出流
在Java的lo流中专门提供了用于字符输出的流对象PrintWriter。该对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符串,并
且可通过println();方法实现自动换行。
public static void main(String[] args) {
BufferedReader br = null;
PrintWriter pw = null;
try{
br = new BufferedReader(new InputStreamReader(new FileInputStream("E:/a.txt")));
pw = new PrintWriter("E:/c.txt");
String temp = "";
int i = 1;
while((temp = br.readLine()) != null){
//自带刷新和换行方法
pw.println("("+i+")"+temp);
i++;
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if (br != null){
br.close();
}
if (pw != null){
pw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
字节数组流
ByteArrayIlnputStream和 ByteArrayOutputStream经常用在需要流和数组之间转化的情况!
字节数组输入流
FilelnputStream是把文件当做数据源。ByteArrayInputStream 则是把内存中的”字节数组对象”当做数据源。
public static void main(String[] args) {
byte[] arr = "abcdefg".getBytes();
ByteArrayInputStream bis = null;
StringBuilder sb = new StringBuilder();
try{
//该构造方法的参数是一个字节数组(数据源)
bis = new ByteArrayInputStream(arr);
int temp = 0;
while((temp = bis.read()) != -1){
sb.append((char)temp);
}
System.out.println(sb.toString());
}finally{
try{
bis.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
字节数组输出流
BvteArravOutputStream流对象是将流中的数据写入到字节数组中。
public static void main(String[] args) {
ByteArrayOutputStream bos = null;
try{
StringBuilder sb = new StringBuilder();
bos = new ByteArrayOutputStream();
bos.write('a');
bos.write('b');
bos.write('c');
//将字节输出流转换成字节数组
byte[] arr = bos.toByteArray();
for (int i = 0; i < arr.length; i++) {
sb.append((char)arr[i]);
}
System.out.println(sb.toString());
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(bos != null){
bos.close();
} }catch(Exception e){
e.printStackTrace();
}
}
}
数据流
- 数据流将“基本数据类型与字符串类型"作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型。
- DataInputStream和DataOutputStream提供了可以存取与机器无关的所有Java基础类型数据(如: int、double、String 等)的方法。
- 读取和写入都预先规定了数据类型
- 如何提前知道要读取数据的类型呢?每次读取的数据类型不同,每次都需要调用不同的方法吗?
数据输出流
public static void main(String[] args) {
DataOutputStream dos = null;
try{
dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("E:/data")));
dos.writeChar('a');
dos.writeInt(10);
dos.writeDouble(Math.random());
dos.writeBoolean(true);
dos.writeUTF("你好尚学堂");
dos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(dos != null){
dos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
数据输入流
public static void main(String[] args) {
DataInputStream dis = null;
try{
dis = new DataInputStream(new BufferedInputStream(new FileInputStream("E:/data.txt")));
//直接读取数据,注意:读取的顺序和写入的顺序一致,否则不能正确读取
System.out.println("char: " + dis.readChar());
System.out.println("int: " + dis.readInt());
System.out.println("double: " + dis.readDouble());
System.out.println("boolean: " + dis.readBoolean());
System.out.println("UTF: " + dis.readUTF());
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(dis != null){
dis.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
对象流
对象的本质是用来组织和存储数据的,对象本身也是数据。那么,能不能将对象存储到硬盘上的文件中呢?能不能将对象通过网络传输到另一个电脑呢?我们可以通过序列化和反序列化来实现这些需求。
Java对象的序列化和反序列化
- 当两个进程远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过 http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。
- 把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。
- 对象序列化的作用有如下两种:
- 持久化:把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中。
- 网络通信:在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。
序列化涉及的类和接口
- ObjectOutputStream代表对象输出流,它的 writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
- ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
- 只有实现了Serializable接口的类的对象才能被序列化。Serializable接口是一个空接口,只起到标记作用。
操作基本数据类型
我们前边学到的数据流只能实现对基本数据类型和字符串类型的读写,并不能对Java对象进行读写操作(字符串除外),但是在对象流中除了能实现对基本数据类型进行读写操作l以外,还可以对Java对象进行读写操作。
写出基本数据类型数据
public static void main(String[] args) {
ObjectOutputStream oos = null;
try{
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("E:/001.txt")));
oos.writeInt(10);
oos.writeChar('v');
oos.writeBoolean(false);
oos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(oos != null){
oos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
读取基本数据类型数据
public static void main(String[] args) {
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("E:/001.txt")));
//必须按照写入的顺序读取(类型)
System.out.println("int: "+ois.readInt());
System.out.println("char: "+ois.readChar());
System.out.println("boolean: "+ois.readBoolean());
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(ois != null){
ois.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
操作对象
【将对象序列化到文件】objectOutputStream可以将一个内存中的Java对象通过序列化的方式写入到磁盘的文件中。被序列化的对象必须要实现Serializable序列化接口,否则会抛出异常。
创建对象
//必须带有serializable接口的标记
public class Users implements Serializable {
private int userid;
private String username;
private String userage;
public Users() {
}
public Users(int userid, String username, String userage) {
this.userid = userid;
this.username = username;
this.userage = userage;
}
public int getUserid() {
return userid;
}
public void setUserid(int userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUserage() {
return userage;
}
public void setUserage(String userage) {
this.userage = userage;
}
}
序列化对象
ObjectOutputStream oos = null;
try{
oos =new ObjectOutputStream(new FileOutputStream("E:/001"));
Users u1 =new Users(001,"cyf","25");
oos.writeObject(u1);
oos.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(oos != null){
oos.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
将对象反序列化到内存中
public static void main(String[] args) {
ObjectInputStream ois = null;
try{
ois = new ObjectInputStream(new FileInputStream("E:/002.txt"));
Users u1 = (Users) ois.readObject();
System.out.println(u1);
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(ois != null){
ois.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
随机访问流
RandomAccessFile 可以实现两个作用:
-
实现对一个文件做读和写的操作
-
可以访问文件的任意位置。不像其他流只能按照先后顺序读取
【三个核心方法】:
- RandomAccessFile(String name,Stringmode) name 用来确定文件; mode取r(读)或rw(可读写),通过mode可以确定流对文件的访问权限
- seek(long a)用来定位流对象读写文件的位置,a确定读写位置距离文件开头的字节个数
- getFilePointer()获得流的当前读写位置。
RandomAccessFile raf = null;
try{
raf = new RandomAccessFile("E:/003.txt","rw");
//先在文件中写入数据
int[] arr = new int[]{10,20,30,40,50,60,70,80,90,100};
for (int i = 0; i < arr.length; i++) {
raf.writeInt(arr[i]);
}
/**
* 先选定要读取数据的位置,在给定类型(必须明确类型对应的字节数量)
* seek方法中输入的必须是读取数据对应的第一个字节的索引
*/
raf.seek(20);
System.out.println(raf.readInt());
//隔一个数据一读取
for (int i = 0; i < 10; i+=2) {
raf.seek(i*4);
System.out.print(raf.readInt()+"\t");
}
System.out.println();
//在第8个字节位置插入新的数据,替换原来的数据30
raf.seek(8);
raf.writeInt(45);
// for (int i = 0; i < 10; i++) {
// raf.seek(0);错误写法,如此写,每次循环都从索引0开始读4个字节,每次循环结果都是10
// System.out.print(raf.readInt()+"\t");
// }
for (int i = 0; i < 10; i+=2) {
raf.seek(i*4);
System.out.print(raf.readInt()+"\t");
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(raf != null){
raf.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
File类在IO中的作用
当以文件作为数据源或目标时,除了可以使用字符串作为文件以及位置的指定以外,也可以使用File类指定。
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try{
br = new BufferedReader(new FileReader(new File("E:/001.txt")));
bw = new BufferedWriter(new FileWriter(new File("E:/004.txt")));
String temp = "";
int i = 1;
while((temp = br.readLine()) != null){
bw.write(i+"、"+temp);
bw.newLine();
i++;
}
bw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(br != null){
br.close();
}
if(bw != null){
bw.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}