java io流 输入输出处理(笔记)
文章目录
一、File类的使用
File类是对文件和目录路径名的抽象表示形式。
1.构造方法
File(String pathname)*
通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
File(File parent, String child)
根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
File(String parent, String child)
根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File file = new File("d:\\1109test.txt");
File file2 = new File("d:/","newFile2");
File file3 = new File(file2,"aaa");
2.绝对路径与相对路径
绝对路径:指的是完整的路径,例如:D:\Download\test.txt
相对路径:指的是没有带盼复的路径,默认在当前文件项目的根目录下
3.File类常用方法
System.out.println(file.exists()); //判断是否存在文件
System.out.println(file.isFile()); //在创建文件后判断是否与为文件
System.out.println(file.length()); //file的大小(字节)
System.out.println(file.getAbsolutePath()); //获取绝对路径
System.out.println(file.getPath()); //获取相对路径
System.out.println(file.getName()); //获取名字
System.out.println(file.delete()); //删除文件
二、io流的概念
1.了解流的概念
Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。
注:java中的输入和输出流都是相对于计算机内存(或者说应用程序)来说
2.java流的分类
二、FileInputStream类与FileOutputStream类(字节流)
1.FileInputStream
注:在创建FileInputStream实例的时候,如果指向了一个不存在的文件,则会导致FileNotFoundException
FileInputStream fis = null;
try {
fis = new FileInputStream("d:/1109test.txt");
int data;
byte[] b = new byte[100];
while ((data = fis.read(b)) != -1) {
System.out.println(data); //输出data
System.out.println(b); //b的地址
for (int i = 0; i < b.length; i++) {
System.out.println((char) b[i]); //将b[i]强制转化为字符输出
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close(); //关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
}
2.FileOutputStream
注:再用FileOutputStream创建实例的时候,如果还文件不存在,则会自动创建一个空文件
FileOutputStream fos = null;
try {
fos = new FileOutputStream("d:\\1109test.txt", true);
//注意输出流构造有append ,默认是false,写入时会覆盖之前的内容,为true改为追加
String info = "我不想学习";
byte[] bytes = info.getBytes(); //将info转化为byte数组
//write方法的重载,off指write的起始位置,int表示写入的字符数
fos.write(bytes, 0, bytes.length);
//将缓冲区中的内容强制写到对象之中(没有也能写入,但最好加上,以免意外)
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close(); //在finally中关闭输出流
} catch (IOException e) {
e.printStackTrace();
}
}
3.可能会遇到的问题
①通过while循环读写文件时,读写两次
while (fis.read()!=-1){
System.out.println(fis.read());
}
在while判断中,进行了一次读的操作,在while方法体重又进行了一次读的操作,一次循环进行了两次读的操作,应当改为以下
int data;
byte[] b = new byte[100];
while ((data = fis.read(b)) != -1) {
System.out.println(data);
System.out.println(b);
for (int i = 0; i < fis.available(); i=i) {
//注意available会实时变化
System.out.println((char) fis.read());
}
②FileOutputStream的write方法重载
void write(byte[] b)
将 b.length 个字节从指定 byte 数组写入此文件输出流中。
void write(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。这种情况下要注意偏移量和文本长度length,可能会导致越界
三、FileReader类和FileWriter类(字符流)
1.FileReader
字符流适用于文本文件的读写,OutputStreamWriter类其实也是借助FileOutputStream类实现的,故其构造方法是FileOutputStream的对象
public static void test4() { //FileReader类内容
FileReader fr = null;
try {
fr = new FileReader("d:\\iofile.txt"); //创建FileReader对象
int len = -1;
StringBuffer s = new StringBuffer();
char[] chars = new char[20];
while ((len = fr.read(chars)) != -1) {
//读取fr对象中的内容到chars(字符数组中),当值为-1时即代表没有下一位
System.out.println(len);
s.append(chars);
}
System.out.println(s); //输出
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
如果想要解决中文乱码的问题(中文占用3个字符位),可以使用Reader的子类InputStreamReader,
OutputStreamWriter同理也可以处理Writer类中的中文乱码问题
源码如下: 通过重载的带有charSet的构造来指定使用的编码格式
public class InputStreamReaderStu {
public static void main(String[] args) {
Reader fr = null;
try {
FileInputStream fis = new FileInputStream("d:/iofile.txt");
fr = new InputStreamReader(fis, "utf-8"); //设置编码格式为utf-8
StringBuffer s = new StringBuffer();
char[] ch = new char[20];
int len = -1;
while ((len = fr.read(ch))!=-1){
s.append(ch);
}
System.out.println(s);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fr.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileWriter
public static void test5() { //FileWriter类内容
FileWriter fw = null;
try {
fw = new FileWriter("d:/iofile.txt", true); //创建对象
String s = new String("我不想学习"); //设置要输出的的内容
fw.write(s);
fw.flush; //强制写入
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fw.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
四、BufferReader类和BufferedWriter类(字符缓冲流)
public static void test6() { //BufferedReader类相关内容
//BufferedReader继承reader,需要填入一个reader对象
BufferedReader br = null;
//InputStreamReader继承reader,需要填入一个输入流对象
InputStreamReader isr = null;
FileInputStream fis = null; //字节流
try {
fis = new FileInputStream("d:/test/bufferedreader.txt");
//构造方法的重载,可以填入读内容时的编码格式
isr = new InputStreamReader(fis, "utf8");
br = new BufferedReader(isr);
String s = new String();
//BufferedReader和FileReader类新增readline()方法
while ((s = br.readLine()) != null) {
System.out.println(s); //作用是读取一整行
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//try/catch快捷键---->选中需要try/catch的内容 ctrl+alt+t
br.close();
isr.close();
fis.close(); //关闭所有的流
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void test7() { //BufferedWriter类相关内容
//继承writer类,需要填入一个writer对象
BufferedWriter bw = null;
//继承writer类,需填入一个输出流对象(OutputStreamWriter)
OutputStreamWriter osw = null;
FileOutputStream fos = null; //输出流对象
try {
//append追加,默认false,即覆盖
fos = new FileOutputStream("d:/test/bufferedreader.txt", true);
osw = new OutputStreamWriter(fos);
bw = new BufferedWriter(osw);
String s = new String("学习使我快乐");
bw.write(s);
bw.newLine(); //newline()方法--->创建一行空白行
bw.write(s);
bw.flush(); //强制将缓冲区内的内容写入到fis流对象pathname中
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bw.close();
osw.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、读写二进制文件
我们可以通过DataInputStream和DataOutputStream配合输入输出流来进行读写二进制
public static void test8() { //读写二进制文件(利用DataInputStream和DataOutputStream)配合输入输出流来进行
DataInputStream dis =null;
FileInputStream fis = null;
DataOutputStream dos = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("./resources./gif.gif"); //输入操作
dis = new DataInputStream(fis);
//输出操作,如果路劲不存在,则默认在项目路径下创建
fos = new FileOutputStream("gifcopy.gif");
dos = new DataOutputStream(fos);
int temp = -1; //使用一个临时变量来记录内容
//当读到的内容不是最后一位的时候,就继续往下读
while ((temp = dis.read())!=-1){
dos.write(temp); //利用临时变量完成写入
dos.flush(); //强制写入
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
dos.close();
fos.close();
dis.close();
fis.close();
} catch (IOException e) { //关闭流
e.printStackTrace();
}
}
}
六、序列化与反序列化
序列化 (Serialization)是将对象的状态信息写入到特定流的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
1.先新建一个对象类,方便后续序列化进行
static class person implements Serializable{
//被序列化对象类需要实现serializable接口,否则会报错
//并且对象被序列化后再增改类的属性,会导致类的序列号uid变化,
//后续反序列化会报无效类异常 ------>Exception in thread "main" java.io.InvalidClassException
private String name;
private String gender;
private int age;
public person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
2.序列化
public static void test9() {
//序列化
// 序列化是将对象的状态写入到特定的流中的过程
//对象输出流ObjectOutputStream
//结合FileOutputStream使用,实现对象的序列化
person person = new person("小菜鸡","男",9999999); //新建一个person对象
FileOutputStream fos = null;
//继承OutputStream,需要填入一个输出流对象
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("d:/test/personSeria.txt");
oos = new ObjectOutputStream(fos);
//调用writeObject()方法,填入要序列化的对象
oos.writeObject(person);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
oos.close();
fos.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.反序列化
反序列化就是将保存在文件中的内容重新读取出来,并且把字节序列还原成原先的java对象
public static void test10() { //反序列化
ObjectInputStream ois = null;
FileInputStream fis = null;
try {
fis = new FileInputStream("d:/test/personSeria.txt");
ois = new ObjectInputStream(fis);
//readObject()方法返回一个被对象,要用对象的类来接受
person person2 = (person) ois.readObject();
System.out.println(person2.toString()); //调用toString方法打印信息
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
ois.close();
fis.close(); //关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.序列化与反序列化注意事项
①被序列化对象所在的类需要实现serializable接口,否则会报错
声明接口之后,正常运行代码,没有报错
②被序列化的类进行属性的增改之后,会改变该类的序列序列号uidserialVersionUID
- serialVersionUID是序列化前后的唯一标识符
- 如果没有自己声明一个,那么会使用默认生成的随机序列号
之后进行反序列化就会因为两次对象的序列号不一致而报错
后续反序列化会报无效类异常 ------>Exception in thread “main” java.io.InvalidClassException
这里我手动给类设置了序列号为100l,而不是默认生成的序列号,应为序列化以前的是默认序列号,之后使用的是手动添加的,两次不一致导致无效类异常
因此在使用序列化与反序列化的过程中要注意对对象类的操作可能会导致反序列化失败