FileInputSteam
:用于读取诸如图像数据的原始字节流
FileInputStream常用方法:
FileInputStream(File file)
//创建文件输入流read()
//从该输入流读取一个字节的数据read(byte[] b)
//从该输入流读取最多b.length
个字节的数据为字节数组。read(byte[] b, int off, int len)
//从该输入流读取最多len
字节的数据为字节数组。
读文件
mport java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInput {
public static void main(String[] args) throws IOException {
//utf-8进行存储,一个英文字母占一个字节,一个中文占3个字节
//如果文本文件,那么就不要使用字节流读取了,建议使用字符流
//read()读取一个字节,返回int类型,都是正数
//方式一:
Input01();
//方式二
Input02();
}
public static void Input01() throws IOException {
//利用字节流读取文件
File file = new File("E:\\test.txt");
FileInputStream fi = new FileInputStream(file);
int read = fi.read();
while(read!=-1){
System.out.print((char)read);
read=fi.read();
}
fi.close();
}
public static void Input02() throws IOException {
FileInputStream fi=new FileInputStream(new File("E:\\test.txt"));
byte[] b=new byte[8];
int len=fi.read(b);
while(len!=-1){
for(int i=0;i<len;i++){
System.out.print((char) b[i]);
}
len=fi.read(b);
}
fi.close();
}
}
FileOutputStream
用于写入诸如图像数据的原始字节流。
FileOutputStream常用方法:
FileOutputStream(File file)
//创建文件输出流以写入由指定的File
对象表示的文件。FileOutputStream(File file,boolean append)
//创建文件输出流以覆盖(false)或者追加(true)的方式写入。write(int b)
//将指定的字节写入此文件。write(byte[] b)
//将b.lenth
个字节从指定数组写入此文件中。
写文件
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class FileOutput {
public static void main(String[] args) throws IOException {
FileOutputStream fo=new FileOutputStream(new File("E:\\demo.txt"));
String str="hello java!";//写入的内容
byte[] b = str.getBytes(StandardCharsets.UTF_8);//按utf-8编码格式转成字节数组
fo.write(b);//写入操作
fo.close();//关闭流
}
}
import java.io.*;
public class FileCopy {
public static void main(String[] args) throws IOException {
File f1 = new File("E:\\test.txt");
File f2 = new File("E:\\demo.txt");
FileInputStream fi = new FileInputStream(f1);
FileOutputStream fo = new FileOutputStream(f2);
byte[] b = new byte[8];
int len = fi.read(b);
while (len != -1) {
fo.write(b, 0, len);
len = fi.read(b);
}
fo.close();
fi.close();
}
}
FileReader
:是用于读取字符流。
FileReader常用方法:
new FileReader(File file);
//构造方法read();
//每次读取单个字符,返回该字符,如果读到文件末尾返回-1read(char[] ch);
//读取多个到数组,返回读取到的字符数,如果到文件末尾返回-1
读文件
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class FileRead {
public static void main(String[] args) throws IOException {
//方式一
Read01();
//方式二
Read02();
}
public static void Read01() throws IOException {
String path = "E:\\Test\\test01.txt";
File file = new File(path);
FileReader fileReader = new FileReader(file);
int read = fileReader.read();
while (read != -1) {
System.out.print((char) read);
read = fileReader.read();
}
fileReader.close();
}
public static void Read02() throws IOException {
File file = new File("E:\\Test\\test01.txt");
FileReader fileReader = new FileReader(file);
char[] ch = new char[8];
int len = fileReader.read(ch);//缓冲数组
while (len != -1) {
// for (int i=0;i
// System.out.print(ch[i]);
// }
// len=fileReader.read(ch);
//将数组转为string
String str = new String(ch, 0, len);
System.out.print(str);
len = fileReader.read(ch);
}
fileReader.close();
}
}
FileWriter
:是用于写入字符流。
FileWriter常用方法:
new FileWriter(File file,boolean true);
//构造方法,如果目标文件不存在,就自动创建该文件,默认为false,对源文件进行覆盖操作,true,对源文件末尾进行追加。write();
//写入单个字符write(char[] ch);
//写入指定数组内容,也可写入数组的指定部分write(String str);
//写入指定字符串,也可写入字符串的指定部分
注意:FileWriter使用后,必须要关闭(close)或者刷新(flush),否者写入不到指定文件!
写文件
import java.io.*;
public class FileWrite {
public static void main(String[] args) throws IOException {
//一个一个字符写入
// new FileWriter(file,false)对源文件按进行覆盖操作
// new FileWriter(file,true)对源文件进行追加,而不是覆盖
Write01();
//利用缓冲数组输出
Write02();
}
public static void Write01() throws IOException {
//如果目标文件不存在的话,那么会自动创建此文件
File file = new File("E:\\test.txt");
FileWriter fileWrite = new FileWriter(file, true);
String str = "hello java!!!";
for (int i = 0; i < str.length(); i++) {
fileWrite.write(str.charAt(i));
}
fileWrite.close();
}
public static void Write02() throws IOException {
File file = new File("E:\\test.txt");
FileWriter fileWriter = new FileWriter(file, true);
String str = "你好,java!";
char[] chars = str.toCharArray();
fileWriter.write(chars);
fileWriter.close();
}
}
import java.io.*;
//注意:不要用字符流去操作非文本文件
/*
* 文本文件:.txt/.java/.c/.cpp-->建议使用字符操作
* 非文本文件:.jpj/.mp3/.mp4/.doc/.ppt-->建议使用字节流操作
* */
public class FileCopy {
public static void main(String[] args) throws IOException {
//有一个源文件和一个目标文件
File f1 = new File("E:\\test.txt");
File f2 = new File("E:\\demo.txt");
//输入输出
FileReader fileReader = new FileReader(f1);
FileWriter fileWriter = new FileWriter(f2);
//一个一个字符复制
// int read=fileReader.read();
// while (read!=-1){
// fileWriter.write(read);
// read=fileReader.read();
// }
//利用字符数组
char[] ch=new char[1024];
int len=fileReader.read(ch);
while(len!=-1){
String str=new String(ch,0,len);
fileWriter.write(str);
//fileWriter.write(ch,0,len);
len=fileReader.read(ch);
}
//关闭流
fileWriter.close();
fileReader.close();
}
}
一般情况下,我们使用字节字符流时,每次都是从源文件中读取/写入数据,这种操作效率比较低。
而利用缓冲(处理流),在程序(内存)里开辟一个缓冲区,然后在缓冲区里进行数据的读写,这样就不用每次都到源文件中操作。
缓冲流的使用
- 创建文件对象(new File())
- 创建输入输出流对象(new FileInputStream()/new FileReader())
- 创建缓冲流对象(new BufferedInputStream(fi)/new BufferedReader(fr))
- 利用缓冲流操作读写(read()/write())
- 关闭流(bf.close())
如果处理流包裹着节点流的话,那么其实只要关闭高级流(处理流),那么里面的字节流也会随之被关闭。
当创建BufferedInputStream
时,将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次有多个字节。
BufferedOutputStream
实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。
常用方法:
new BufferedInputStream(InputStream in)
//创建一个 BufferedInputStream并保存其参数,输入流 innew BufferedInputStream(InputStream in,int size)
//创建 BufferedInputStream具有指定缓冲区大小,并保存其参数,输入流 inread()
//与InputStream中read()
用法相同read(byte[] b,int off,int len)
// 与InputStream中read(byte[] b,int off,int len)
相同BufferedOutputStream(OutputStream out)
//创建一个新的缓冲输出流,以将数据写入指定的底层输出流。BufferedOutputStream(OutputStream out, int size)
//创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流write(byte[] b, int off, int len)
//从指定的字节数组写入 len个字节,从偏移 off开始到缓冲的输出流。write(int b)
//将指定的字节写入缓冲的输出流。
利用缓冲字节流对文件的拷贝
import java.io.*;
public class BufferedStream {
public static void main(String[] args) throws IOException {
FileInputStream fi = new FileInputStream(new File("E:\\test.txt"));
FileOutputStream fo = new FileOutputStream(new File("E:\\demo.txr"));
BufferedInputStream bis=new BufferedInputStream(fi);
BufferedOutputStream bos=new BufferedOutputStream(fo);
byte[] b=new byte[1024];
int len=bis.read(b);
while(len!=-1){
bos.write(b,0,len);
len=bis.read(b);
}
bos.close();
bis.close();
}
}
在使用字符缓冲流读文件时,使用
readLine()
可以读一行文字,返回的是一个字符串,如果我们要对这读取到这一行进行写操作时,就要手动的在下面添加换行,newLine()
,不然的话会把所有的内容都写在同一行
利用缓冲字符流对文件的拷贝
import java.io.*;
public class BufferedRW {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader(new File("E:\\test.txt"));
FileWriter fw=new FileWriter(new File("E:\\demo.txt"));
BufferedReader bfr=new BufferedReader(fr);
BufferedWriter bfw=new BufferedWriter(fw);
String str=bfr.readLine();
while(str!=null){
bfw.write(str);
bfw.newLine();
str=bfr.readLine();
}
bfw.close();
bfr.close();
}
}
System.out
:标准的输出流,默认情况下输出到控制台,返回的是打印流(PrintStream)
import java.io.PrintStream;
public class Test {
public static void main(String[] args) {
PrintStream out = System.out;
out.print("hello");//直接在控制台上写出,不换行
out.println("java");//直接在控制台上写出,并且换行操作
System.out.println("hello world");
}
}
System.in
:标准输入流,默认情况下,从键盘输入
Scanner
:起扫描作用,扫描从键盘上输入的数据,还可以扫描其他流的数据
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class input {
public static void main(String[] args) throws IOException {
InputStream in = System.in;//得到标准的输入流
int a=in.read();
System.out.println(a);
//Scanner可以扫描其他流的数据
Scanner sc=new Scanner(System.in);
int b=sc.nextInt();
System.out.println(b);
//Scanner扫描文件
Scanner input=new Scanner(new FileInputStream(new File("E:\\test.txt")));
while(input.hasNext()){
System.out.println(input.next());
}
}
}
转换流的作用
将字节流和字符流进行转换
转换流属于字节流还是字符流?
属于字符流
InputStreamReader:字节输入流–>字符输入流
OutputStreamWriter:字符输出流–>字节输出流
import java.io.*;
public class Test02 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws IOException {
//1.有一个源文件
File f1 = new File("d:\\Test.txt");
//2.有一个目标文件:
File f2 = new File("d:\\Demo.txt");
//3.输入方向:
FileInputStream fis = new FileInputStream(f1);
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
//4.输出方向:
FileOutputStream fos = new FileOutputStream(f2);
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//5.开始动作:
char[] ch = new char[20];
int len = isr.read(ch);
while(len!=-1){
osw.write(ch,0,len);
len = isr.read(ch);
}
//6.关闭流:
osw.close();
isr.close();
}
}
数据流:就是用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串写入内存变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中
利用DataOutputStream向外写出变量
public class Test01 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws IOException {
//DataOutputStream: 将内存中的基本数据类型和字符串的变量 写出 文件中
File f = new File("d:\\Demo2.txt");
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos = new DataOutputStream(fos);
//向外将变量写到文件中去:
dos.writeUTF("你好");
dos.writeBoolean(false);
dos.writeDouble(6.9);
dos.writeInt(82);
//关闭流:
dos.close();
}
}
打开文件可以看到,内容我们看不懂,这是给程序看的
我们用程序读取
import java.io.*;
public class Test02 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws IOException {
//DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中
DataInputStream dis = new DataInputStream(new FileInputStream(new File("d:\\Demo2.txt")));
//将文件中内容读取到程序中来:
System.out.println(dis.readUTF());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
//关闭流:
dis.close();
}
}
数据流:就是用来操作基本数据类型和字符串的
DataInputStream:将文件中存储的基本数据类型和字符串写入内存变量中
DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中
序列化和反序列化
序列化就是在保存数据时,保存数据的值和数据类型
反序列化就是在恢复数据时,恢复数据的值和数据类型
需要让某个对象支持序列化和反序列化机制,则必须让其类是可序列化的,为了让某个类可序列化的,该类必须实现两个接口之一:
Serializable
:标记接口,接口内部,什么都没有,这种接口叫 标识接口。起到标识作用,标识什么呢?只要实现这个接口的类的对象才能序列化,否则不可以。Externalizable
:一般不使用
serialVersionUID:凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量
- private static final long serialVersionUID
- serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容
- 如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
- 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
序列化细节:
- 被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)
- static,transient修饰的属性 不可以被序列化。
public class Person implements Serializable {
private static final long serialVersionUID = 8027651838638826533L;
private transient String name;
private static int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试方法
public class Test01 {
public static void main(String[] args) throws IOException {
//序列化:将内存中对象 ---》 文件:
//有一个对象:
Person p = new Person("张三",19);
//有对象流:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:\\Demo4.txt")));
//向外写:
oos.writeObject(p);
//关闭流:
oos.close();
}
}
public class Test02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:\\Demo4.txt")));
//读入内存:
Person p = (Person)(ois.readObject());
System.out.println(p);
//关闭流:
ois.close();
}
}