使用Java实现面向对象编程——第八章 File IO
Posted 智者乐水
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Java实现面向对象编程——第八章 File IO相关的知识,希望对你有一定的参考价值。
1、文件:文件可认为是相关记录或放在一起的数据的集合;
2、File类:名命空间:java.io
File对象即可表示文件,也可表示目录, 在程序中,一个File对象可以代表一个文件或目录, 利用他可以 用来对文件或目录进行基本操作; 创建一个File文件的语法: File file = new File( String pathname ); //pathname表示文件路径: 格式:"c:\\\\test .txt" 或 "c:/test .txt" |
File常用的方法:
|
2、流:流是指一连串流动的字符,是以先进先出的方式发送和接收数据的通道;
★读文件:把文件中的数据读到内存中
★写文件:把内存中的数据写到文件中;
●Java流的分类:
输入流:只能从中读取数据,而不能向其中写入数据; 输出流:只能向其中写入数据,而不能从中读取数据; |
字节流是 8 位通用字节流,1字节; 字符流是 16 位 Unicode 字符流:2字节 |
输入输出流是相对于计算机内存来说的:
|
字节流建议用与二进制数据(如图片),字符流用于文本; 下面的四个基类都是抽象类:
|
3、文件的读写:
●文本文件的读写:用FileInputStream和FileOutputStream读写文本文件、用BufferedReader和BufferedWriter读写文本文件
●二进制文件的读写:使用DataInputStream和DataOutputStream读写二进制文件
●使用字节流读取文件:
字节输入流InputStream类:将文件中的数据输入到内部存储器(内存)中; ●InputStream类常用方法 ●int read( ):读取一个字节数据; ★无参的read():从输入流读取一个八位的字节,把它转换为0~255的整数返回; ★带参的read():从输入流批量读取若干个字节, 从文件或键盘读取数据时,采用下面两种方法可以减少进行物理读取文件或键盘的次数,提高输入输出效率 ●int read(byte[] b) :将数据读取到字节数组中; ●int read(byte[] b,int off,int len):从输入流中读取最多len长度的字节,保存到字节数组b中,保存的位置从off开始; ●void close( ):关闭输入流; ◆int available():返回输入流读取的估计字节数; |
|
字节输入流FileInputStream 类: ●子类FileInputStream常用的构造方法 ◆FileInputStream(File file):file指定文件数据源。 File file=new File(“C:\\\\test.txt”); InputStream fileObject=new FileInputStream(file); ◆FileInputStream(String name):name指定文件数据源,包含路径信息。 InputStream in=new FileInputStream(“C:\\\\text.txt”); |
|
使用FileInputStream 读文本文件步骤: ★引入相关的类 ★构造文件输入流FileInputStream 对象 ★读取文本文件的数据 ★关闭文件流对象 |
|
Eg:
输出结果:
|
Eg:省略了代码
输出结果:
|
●使用字节流写入文本文件:
字节输出流OutputStream类:把内存中的数据输出到文件中 ●OutputStream类常用方法 void write(int c):写入一个字节数据; void write(byte[] buf):写入数组buf’的所有字节; void write(byte[] b,int off,int len):将字节数组中从off位置开始,长度为len的字节数据输出到输出流中; void close( ):关闭输出流; |
|
字节输出流FileOutputStream类:实现向文本文件写入数据; ●子类FileOutputStream常用的构造方法 ●FileOutputStream (File file):file指定文件目标数据源; File file=new File(“C:\\\\test.txt”); FileOutputtream fos=new FileOutputStream(file); ●FileOutputStream(String name) :name指定文件目标数据源,包含路径信息; FileOutputStream fos=new FileOutputStream(“C:\\\\test.txt”); ●FileOutputStream(String name,boolean append)://name指定文件目标数据源,包含路径信息;//append表示是否在文件末尾添加数据;设置为true,则在文件末尾添加数据。 FileOutputStream fos=new FileOutputStream(“C:\\\\test.txt”,true); ●注意:第一种和第二种构造方法在向文件写数据时将覆盖文件中原有的内容; 如果相应的文件不存在,就会自动创建一个空的文件; 若参数file和name表示的文件路径尽管存在,但是表示一个文件目录;则会抛出FileNotFoundException异常; |
|
使用FileOutputStream 写文本文件: ★引入相关的类 ★输出流FileOutputStream对象 ★把数据写入文件 ★关闭文件流对象 |
|
Eg:
|
Eg:
|
●使用字节输入输出流进行复制操作:
Eg:关键代码
|
●使用字符流读取文件: Read()是一个抽象类;
字符输入流Reader类: ●字符输入流Reader类常用方法 int read( ):从输入流中读取单个字符; int read(byte[] c):从输入流中读取c.length长度的字符,保存到字符数组c中,保存的位置从off位置开始,返回实际读取的字符数; read(char[] c,int off,int len):从输入流中读取c.length长度的字符,保存到字符数组c中,保存的位置从off位置开始,返回实际读取的字符长度; void close( ):关闭流; |
||
字符输入流FileReader()类: ●子类FileReader()常用的构造方法: FileReader(String filrname) :filename指从中读取数的文件的名称; |
||
使用FileIReader读文本文件步骤: ★引入相关的类 ★创建一个FileReader对象 ★利用FileReader类的方法读取文本文件的数据; ★关闭相应的流对象; |
||
BufferedReader类:;BufferedReader类是Reader类的子类,BufferedReader类带有缓冲区,能够提高读取操作的效率; ●子类BufferedReader常用的构造方法 BufferedReader(Reader in): ●子类BufferedReader特有的方法:用来按行读取内容; readLine() |
||
使用 BufferedReader 读文本文件步骤:
|
||
●Writer类常用方法 write(String str):将str字符串里包含的字符输出到指定的输出流中; write(String str,int off,int len):将Str字符串里从off位置开始长度为len的字符输出到输出流中; void close():关闭输出流; void flush():刷新输出流; |
||
使用使用FileWriter写文件步骤: 1、引入相关的类 2、创建FileWriter对象 3、写文本文件 4、关闭相关的流对象 |
|
|
■子类BufferedWriter常用的构造方法 ◆BufferedReader(Writer out) |
||
使用 BufferedWriter 写文件步骤:
|
4、二进制文件的读写:
●DataInputStream类 ●FileInputStream的子类 ●与FileInputStream类结合使用读取二进制文件 ●DataOutputStream类 ●FileOutputStream的子类 ●与FileOutputStream类结合使用写二进制文件 |
|
使用 DataInputStream 读二进制文件:
|
|
使用 DataOutputStream写二进制文件:
|
5、 附加1:对象流:序列化、反序列化、序列化克隆;
●序列化(Serialization)和反序列化的过程:
序列化:将对象的状态写入到特定的流中的过程; 反序列化:从特定的流中获取数据重新构建对象的过程; |
||
1、序列化与反序列化: 序列化:指把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程 反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。 也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程 2、为什么要做序列化: ①、在分布式系统中,此时需要把对象在网络上传输,就得把对象数据转换为二进制形式,需要共享的数据的 JavaBean 对象,都得做序列化。 ②、服务器钝化:如果服务器发现某些对象好久没活动了,那么服务器就会把这些内存中的对象持久化在本地磁盘文件中(Java对象转换为二进制文件);如果服务器发现某些对象需要活动时,先去内存中寻找,找不到再去磁盘文件中反序列化我们的对象数据,恢复成 Java 对象。这样能节省服务器内存。 3、Java 怎么进行序列化: ①、需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(这是一个标志接口,没有任何抽象方法), Java 中大多数类都实现了该接口,比如:String,Integer ②、底层会判断,如果当前对象是 Serializable 的实例,才允许做序列化,Java对象 instanceof Serializable 来判断。 ③、在 Java 中使用对象流来完成序列化和反序列化 ObjectOutputStream:通过 writeObject()方法做序列化操作 ObjectInputStream:通过 readObject() 方法做反序列化操作 4、什么时候需要序列化: ◆当你想把内存中的对象状态保存到一个文件中或者数据库中; ◆当你想用套接字在网络上传送对象的时候 ◆当你想通过RMI传输文件的时候; 5、打开生成的文件乱码的原因: ◆序列化和反序列化都是基于二进制流的,在将Students的相关信息转化为二进制存储在了Student.bin文件中,用编辑器打开自然是乱码的, 只有通过反序列化才能将存储的二进制文件读取出来,然后显示在控制台上; ◆注意:不是因为写出的编码和文本编辑器的默认编码采用了不一样的字符集; |
||
序列化的步骤:(使用集合保存对象,可以将集合中的所有对象序列化) 实现Serializable接口; 创建对象输出流; 调用writeObject()方法将对象写入文件; 关闭对象输出流; |
||
注意:错误一:如果新建的 Person 对象没有实现 Serializable 接口,那么上面的操作会报错:
|
||
问题1:如果某些数据不需要做序列化,比如密码, 解决办法:在字段面前加上 transient Eg:private String name;//需要序列化 transient private int age;//不需要序列化 那么我们在反序列化的时候,打印出来的就是Person [name=vae, age=0],整型数据默认值为 0 |
||
问题2:序列化版本问题,在完成序列化操作后,由于项目的升级或修改,可能我们会对序列化对象进行修改, 比如增加某个字段,那么我们在进行反序列化就会报错:
解决办法:在 JavaBean 对象中增加一个 serialVersionUID 字段,用来固定这个版本,无论我们怎么修改,版本都是一致的,就能进行反序列化了; Eg:private static final long serialVersionUID = 8656128222714547171L; |
||
代码: /** * 反序列化学生对象 * @author 逆風〠飛翔 * */ public class SerizaableTest1 {
public static void main(String[] args) { //创建对象输入流 FileInputStream fs=null; ObjectInputStream ois=null; try { fs=new FileInputStream("E:\\\\Student.bin"); ois=new ObjectInputStream(fs); Students stu=(Students)ois.readObject(); System.out.println("学生姓名:"+stu.getName()+",学生年龄:"+stu.getAge()+ ",学生性别:"+stu.getGender()+"\\n读取信息成功!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally { if(fs!=null) { try { fs.close(); } catch (IOException e) { e.printStackTrace(); } } if(ois!=null) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } } |
Eg: /** * 序列化学生对象 * @author 逆風〠飛翔 * */ public class SerizableTest { public static void main(String[] args) { //创建一个需要序列化的学生对象 Students stu=new Students("小明", "男", 20); //创建一个对象输出流 OutputStream os=null; ObjectOutputStream oos=null; try { os=new FileOutputStream("E:\\\\Student.bin"); oos=new ObjectOutputStream(os); oos.writeObject(stu); System.out.println("创建Students.bin文件成功!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(os!=null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(oos!=null) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } }
} } |
|
Eg:学生类 public class Students implements Serializable{ private String name; private int age; //不想被序列化的关键字:transient transient private String gender; 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 String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
/** * 带参构造函数 * @param name 姓名 * @param gender 性别 * @param age 年龄 */ public Students(String name,String gender,int age) { this.name=name; this.age=age; this.gender=gender; } } |
||
Eg:用集合进行序列化 import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; /** * 序列化学生对象 * @author 逆風〠飛翔 * */ public class SerializableTest { public static void main(String[] args) { //创建五个需要序列化的学生对象 Students stu=new Students("小明", "男", 20); Students stu1=new Students("小明1", "男", 21); Students stu2=new Students("小明2", "男", 22); Students stu3=new Students("小明3", "男", 23); Students stu4=new Students("小明4", "男", 24); //标记元素类型 List<Students> student = new ArrayList<Students>(); student.add(stu); student.add(stu1); student.add(stu2); student.add(stu3); student.add(stu4); //创建一个对象输出流 OutputStream os=null; ObjectOutputStream oos=null; try { os=new FileOutputStream("E:\\\\Student.bin"); oos=new ObjectOutputStream(os); oos.writeObject(student); System.out.println("创建Students.bin文件成功!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(os!=null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(oos!=null) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } |
Eg:用集合进行反序列化 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.util.List;
/** * 反序列化学生对象 * @author 逆風〠飛翔 * */ public class SerializableTest1 {
public static void main(String[] args) { //创建对象输入流 FileInputStream fs=null; ObjectInputStream ois=null; try { fs=new FileInputStream("E:\\\\Student.bin"); ois=new ObjectInputStream(fs);
List<Students> listStu = (List<Students>) ois.readObject(); System.out.println("学生的人数:"+listStu.size()); for (Students stu : listStu) { System.out.println("学生姓名:"+stu.getName()+", 学生性别:"+stu.getGender()+",学生年龄:"+stu.getAge()); } System.out.println("读取信息成功!");
} catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally { if(fs!=null) { try { fs.close(); } catch (IOException e) { e.printStackTrace(); } } if(ois!=null) { try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } } |
●为克隆实现序列化:java序列化可以将一个对象的状态写入到byte流里,并且能够把byte流里的数据读取出来,重新构造一个相同的对象
public class SerialCloneTest { public static void main(String[] args) { Employee employee=new Employee("小明", 20000, 2018,7,3); Employee employeeOne=(Employee) employee.clone(); employee.raiseSalary(10); System.out.println(employee); System.out.println(employeeOne); } } |
public class Employee extends SerialCloneable{ private String name; private double salary; private Date hireDay; public Employee(String name, double salary, int year,int month,int day) { super(); this.name = name; this.salary = salary; //提供了世界上大多数国家使用的标准日历系统。 GregorianCalendar calendar=new GregorianCalendar(year, month-1, day); this.hireDay=calendar.getTime(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Date getHireDay() { return hireDay; } public void setHireDay(Date hireDay) { this.hireDay = hireDay; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("姓名:" + name + "\\n"); sb.append("薪资:" + salary + " \\n"); sb.append("出生日期:" + hireDay ); return sb.toString(); } public void raiseSalary(double byPercent){ double raise=salary*byPercent/100; salary+=raise; } } |
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable;
public class SerialCloneable implements Cloneable, Serializable { public Object clone() { try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeObject(this); out.close(); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream in = new ObjectInputStream(bin); Object ret = in.readObject(); in.close(); return ret; } catch (IOException e) { return null; } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } } |
6、 附加2:
bin(二进制文件) 二进制文件,其用途依系统或应用而定。一种文件格式binary的缩写。一个后缀名为".bin"的文件,只是表明它是binary格式。比如虚拟光驱文件常用".bin"作为后缀,但并不意味着所有的bin文件都是虚拟光驱文件。一般来讲是机器代码,汇编语言编译后的结果(磁盘操作系统下汇编语言编译后与".com"文件相类似),用debug、WINHEX,U_EDIT等软件可以打开(通常不一定能看得懂是些什么除非学习过汇编语言)。这类 所有的文件,无论后缀名是什么,一律分为两种格式".text" 和".binary"。 二进制文件 概述 二进制文件,其用途依系统或应用而定。 也就是说,一般来讲是机器代码,汇编语言编译后的结果,(磁盘操作系统下汇编语言编译后与".com"文件相类似),用debug、WINHEX,U_EDIT等软件可以打开(通常不一定能看得懂是些什么除非学习过汇编语言)。这类 所有的文件,无论后缀名是什么,一律分为两种格式".text" 和".binary"。 一种文件格式binary的缩写。一个后缀名为".bin"的文件, 只是想表明它是binary格式,但并不表明它与某种应用程序有必然的联系性。 实例 比如虚拟光驱文件常用".bin"作为后缀,但并不意味着所有".bin"文件都是虚拟光驱文件。 如果你的daemon无法正常安装它,说明它很可能不是虚拟光盘。 另外在软件的安装后文件夹中大部分软件或服务器软件都有个 bin 文件夹。 因为 BIN(BINary)其中文是:二进制。 里面存放的一般是可执行的二进制文件,所以我们通常使用较大型的软件时都会发现有这个名称的文件夹。 BIN文件还有一种最可能的是步步高之类学习机的学习文件或者是点读文件,这类文件只有在制定的硬件或者条件下运行,其他一切方法一概都不能打开或者运行该文件。 此外,在linux平台下,其支持多分区结构,bin就是其中之一。 bin 在linux系统分区中表示存放标准系统实用程序; sbin 存放标准系统管理文件; tmp 存放临时文件。 还有一种较为简单的方式:直接将bin文件强制改名为iso文件即可直接用虚拟光驱打开。 |
7、 总结:
8、附加3:
Eg:
分析:根据给定的 File 对象构造一个 FileWriter 对象。 用FileWriter字符流的时候一定要调用flush()方法写进文件 或者是调用close();关闭流,才能写进文件。 |
Eg:
分析:FileOutputStream的write方法有三类参数的重载,其中一个为int类型参数。 就这个程序片段,语法和调用参数等都没有问题, 其中fos.write(‘a’),会自动进行转换’a’为int类型(ascii编码), 当运行结束,并用记事本打开文件时,其中应该为字符a,答案为C |
Eg:
分析:该题考查InputStream及其子类的使用。 InputStream为抽象类,不能实例化,只能实例化其子类对象。 |
Eg:
分析:首先,File类可以表示路径,所以A答案错误, 其次,程序中的getParentFile方法是返回上一级目录(project目录)的Flie对象,所以list方法返回的应该是上一级,也就是project目录下的对象数组,答案B错误, 最后,list方法返回值是包括了目录和对象的,所以答案D错误。 |
以上是关于使用Java实现面向对象编程——第八章 File IO的主要内容,如果未能解决你的问题,请参考以下文章 |