1、目标
了解输入输出的概念
使用FIle类操作文件或目录
理解流的概念及分类
会使用字节流读写文本文件
会使用字符流读写文本文件
会使用字节流读写二进制文件
使用序列化和反序列化保持和恢复对象信息
2、java I/O
2.1 文件
什么是文件?
相关记录或放在一起的数据的集合
文件一般存储在哪?
java程序如何访问文件属性
java API: java.io.File类
File类访问文件属性
File file = new File(String pathname);
File类常用方法
方法名称 | 说明 |
boolean exists( ) | 判断文件或目录是否存在 |
boolean isFile( ) | 判断是否是文件 |
boolean isDirectory( ) | 判断是否是目录 |
String getPath( ) | 返回此对象表示的文件的相对路径名 |
String getAbsolutePath( ) | 返回此对象表示的文件的绝对路径名 |
String getName( ) | 返回此对象表示的文件或目录的名称 |
boolean delete( ) | 删除此对象指定的文件或目录 |
boolean createNewFile( ) | 创建名称的空文件,不创建文件夹 |
long length() | 返回文件的长度,单位为字节, 如果文件不存在,则返回 0L |
package Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Test01 {
public static void main(String[] args) throws Exception {
//File类的使用
String path = "G:\\xxx\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test000";
File file = new File(path);
//判断文件是否存在
System.out.println(file.exists());
//判断是否时文件
System.out.println(file.isFile());
//判断是否为目录
System.out.println(file.isDirectory());
//返回此对象表示的文件的相对路径
System.out.println(file.getPath());
//返回此对象表示的文件的绝对路径
System.out.println(file.getAbsolutePath());
//返回此对象表示的文件或目录名称
System.out.println(file.getName());
//删除此对象指定的文件或目录
System.out.println(file.delete());
//创建名称的空文件。不创建文件夹
System.out.println(file.createNewFile());
//返回文件的长度,单位为字节,入果文件不存在,返回0L
System.out.println(file.length());
}
}
读写文件
通过流来读写文件
流 是一组有需的数据序列
以先进先出的方式发送信息的通道
java流的分类
输入输出流是相对于计算机内存来说的
字节流是 8 位通用字节流,字符流是 16 位 Unicode 字符流
FileInputStream
inputStream类常用方法
int read( )
int read(byte[] b)
int read(byte[] b,int off,int len)
void close( )
int available():可以从输入流中读取的字节数目
子类FileInputStream常用的构造方法
FileInputStream(File file)
FileInputStream(String name)
使用FIleInputStream读文本文件
FileOutputStream
OutputStream类常用方法
void write(int c)
void write(byte[] buf)
void write(byte[] b,int off,int len)
void close()
void flush():强制把缓冲区的数据写到输出流中
子类FileOutputStream常用的构造方法
FileOutputStream (File file)
FileOutputStream(String name)
FileOutputStream(String name,boolean append)
1.前两种构造方法在向文件写数据时将覆盖文件中原有的内容
2.创建FileOutputStream实例时,如果相应的文件并不存在,则会自动创建一个空的文件
使用FileOutputStream 写文本文件
常见错误
package Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Array;
import java.util.ArrayList;
public class Test02 {
public static void main(String[] args) {
File file = new File("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test000");
File file1 = new File("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test0001");
//FileInputStream类常用方法
try{
FileInputStream fis = new FileInputStream(file);
//读取文本文件数据
//文件中有多少字符
System.out.println(fis.available());
//从文件中一个字节 并且以ASII的形式输出 比如这里文件中第一个字符为1,那么输出的就为49
System.out.println(fis.read());
//那么我们这里要想得到文件中的字符,并且输出出来就可以对读取到的内容进行类型转换
System.out.println((char) fis.read());
//这里我们看到输出为2,是我们的第二个字符,这是为什么呢,
// 这是因为read方法执行就像 i++ 一样,每当我们执行一次read,他就会往后偏移一次,所以我们前面已经
// 执行过一次read方法,所以这里我们再次执行read方法指向的就是第二个字符。
//read(byte[] array) - 从文件中读取字节并存储在指定的数组中
byte[] b = new byte[1024];
//这里我们看到read方法返回值为9,这是因为这里的read不再是指向了,而是把它当前在文件中的位置以及之后的
//数据全部读出并写入到b数组中,并返回所读的字符个数。所以这里的9是它读到并且如b中的字符总数
System.out.println(fis.read(b));
System.out.println(b[0]);
//那么我们再写一次read还能读到字符码
//可以看到这里返回-1,没有读到字符,所以read(b)方法也会改变指向
System.out.println(fis.read());
//read(byte[] array, int start, int length) - 从文件中读取等于length的字节数,
// 并从位置start开始存储在指定的数组中
//我们重新创建一个对象试试
FileInputStream fis1 = new FileInputStream(file1);
byte[] b1 = new byte[1024];
// System.out.println(fis1.read(b1,0,fis1.available()));
for (byte t:b1){
if (t == 0){
// System.out.print((char)t);
break;
}
System.out.print((char)t);
}
//skip()方法
//要丢弃和跳过指定
//的字节数,可以使用skip()方法。例如
//跳过五个字符
//没有返回值
// System.out.println(fis.skip(5));
//关闭服务
// fis.close();
// fis1.close();
//FileOutputStream
//常用方法
File file2 = new File("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test0002");
FileOutputStream fos = new FileOutputStream(file2,true);
//writer,写入字符,与read一样,一个字符一个字符输入,
// 并且会输出到控制台,这里是把输入的数字通过ASII转换为字符输入到文件中
// fos.write(123);
//void write(byte[] array) - 将指定数组中的字节写入输出流
//这里直接使用b1或b会报错,这是因为b和b1里的元素并没有全部被实例化,
// fos.write(b1);
//所以这里需要添加长度来写入 这里使用fis1.read函数来获取写入到b1数组中的数组真正的字符数
int numRead = fis1.read(b1, 0, fis1.available());
System.out.println(numRead);
fos.write(b1,0,numRead);
fis.close();
fis1.close();
fos.close();
}catch (IOException iox){
iox.getStackTrace();
}
}
}
Reader类
reader类常用方法
int read( )
int read(char[] c)
read(char[] c,int off,int len)
void close( )
子类InputStreamReader常用的构造方法
InputStreamReader(InputStream in)
InputStreamReader(InputStream in,String charsetName)
FileReader类
FileReader类是InputStreamReader的子类
FileReader(File file)
FileReader(String name)
该类只能按照本地平台的字符编码来读取数据,用户不能指定其他的字符编码类型
System.out.println(System.getProperty("file.encoding"));
获得本地平台的字符编码类型
使用FileReader读取文件
与字节流FileInputStream类实现文本文件读取步骤类似
引入相关的类
import java.io.Reader;
import java.io.FileReader;
Import java.io.IOExceprion;
创建FileReader对象
Reader fr= new FileReader("D:\\myDoc\\简介.txt");
读取文本文件的数据
fr.read();
关闭相关的流对象
fr.close();
BufferReader类
如何提高字符流读取文本文件的效率
使用FileReader类与BufferedReader类
BufferedReader类是Reader类的子类
BufferedReader类带有缓冲区
按行读取内容的readLine()方法
BufferedReader类
BufferedReader常用的构造方法
BufferedReader(Reader in)
子类BufferedReader特有的方法
readLine()
使用 BufferedReader读文本文件
解决读取时中文乱码
读取包含中文的文本文件时,可能出现中文乱码,怎么办?
FileReader fr = new FileReader("c:\\myDoc\\hello.txt");
BufferedReader br=new BufferedReader(fr);
FileInputStream fis=new FileInputStream("c:\\myDoc\\hello.txt");
//使用InputStreamReader并设置编码格式
InputStreamReader fr=new InputStreamReader(fis,"UTF-8");
BufferedReader br=new BufferedReader(fr);
Writer类
常用方法
write(String str)
write(String str,int off,int len)
void close()
void flush()
子类OutputStreamWriter常用的构造方法
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out,String charsetName)
FileWriter类
FileWriter类是OutputStreamWriter的子类
FileWriter (File file)
FileWriter (String name)
该类只能按照本地平台的字符编码来写数据,用户不能指定其他的字符编码类型
使用FileWriter写文件
BufferedWriter类
如何提高字符流写文本文件的效率?
使用FileWriter类与BufferedWriter类
BufferedWriter类是Writer类的子类
BufferedWriter类带有缓冲区
BufferedWriter常用的构造方法
BufferedWriter(Writer out)
使用 BufferedWriter写文件
读取二进制文件
DataInputStream类
FileInputStream的子类
与FileInputStream类结合使用读取二进制文件
DataOutputStream
FileOutputStream的子类
与FileOutputStream类结合使用写二进制文件
使用DataInputStream读取二进制文件
使用DataOutputStream读取二进制文件
2.2 序列化和反序列化
序列化和反序列化的过程
序列化是将对象的状态写入到特定的流中的过程
反序列化则是从特定的流中获取数据重新构建对象的过程
实现序列化
使用集合保存对象,可以将集合中的所有对象序列化
package Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class xuliehua {
public static void main(String[] args) {
//实现对象的序列化,序列化可以理解为对象以特定的编码形式输出到文件中保存
//实例化User类 注意 User类必须实现接口Serializable, 用于区分被实例化的类
try(
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test01.txt"));
) {
User user = new User("张三","123123123",29);
//创建序列化流
//实现序列化并写入到文件中
oos.writeObject(user);
// oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
实现反序列化
如果向文件中使用序列化机制写入多个对象,那么反序列化恢复对象时,必须按照写入的顺序读取
package Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class fanxuliehua {
public static void main(String[] args) {
//实现反序列化也是需要先创建输入流,然后用我们的对象来接取序列化的对象
try {
ObjectInputStream ois= new ObjectInputStream(new FileInputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\test01.txt"));
User u = (User) ois.readObject();
System.out.println(u);
} catch (Exception e) {
e.printStackTrace();
}
}
}
练习
练习一
需求说明实现查看文件属性、创建和删除文件功能
package exercise01;
import java.io.File;
import java.sql.SQLOutput;
public class Test {
public static void main(String[] args) {
File file= new File("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\exercise01\\test");
//判断是否拿到文件
System.out.println(file.exists());
//判断是否是文件
System.out.println(file.isFile());
//查看文件属性
System.out.println("文件名: " + file.getName());
//相对路径
System.out.println("相对路径:" + file.getPath());
//绝对路径
System.out.println("绝对路径:" + file.getAbsolutePath());
//文件大小
System.out.println("文件大小为:" + file.length());
}
}
练习二
文件“我的青春谁做主.txt”位于D盘根目录下,要求将此文件的内容复制到C:\myFile\my Prime.txt中
package exercise02;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws IOException{
//读取文件
FileInputStream fis = new FileInputStream("G:\\我的青春谁做主.txt");
byte[] b = new byte[100];
// System.out.println(fis.available());
// System.out.println(fis.read());
while (fis.read(b, 0, fis.available()+1)!=-1) {
//将字节数组转换为字符串
System.out.println(new String(b));
}
byte[] b1 = new byte[100];
FileOutputStream fos = new FileOutputStream("F:\\myfile\\my Prime.txt");
FileInputStream fis1 = new FileInputStream("F:\\myfile\\my Prime.txt");
fos.write(b,0,b.length);
while (fis1.read(b1, 0, b1.length)!=-1) {
//将字节数组转换为字符串
System.out.println(new String(b1));
}
fis.close();
fos.close();
}
}
练习三、
按照刚才读取的模板文件pet. template的模板格式保存宠物数据到文本文件,即把{name}、{type}、{master}替换为具体的宠物信息,将替换后的内容写入到C:\myDoc\pet.txt中
package exercise03;
import java.io.*;
public class Test {
public static void main(String[] args) {
try{
String path = "G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\exercise03";
Reader fr = new FileReader(path + "\\template");
BufferedReader br = new BufferedReader(fr);
// System.out.println(br.readLine());
String str1 =br.readLine();
System.out.println(str1);
str1 = str1.replace("{name}","偶偶");
str1 = str1.replace("{type}","狗狗");
str1 = str1.replace("{master}","李伟");
br.close();
fr.close();
Writer fw = new FileWriter(path + "\\pet");
BufferedWriter bw = new BufferedWriter(fw);
bw.write(str1);
bw.flush();
fw.close();
}catch (Exception e ){
e.printStackTrace();
}
}
}
练习四
需求说明图片star.jpg位于C盘根目录下,要求将此图片复制到D:\myDoc\myPicture.jpg需求说明图片star.jpg位于C盘根目录下,要求将此图片复制到D:\myDoc\myPicture.jpg
package exercise04;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) {
try{
//datainputStream的使用,他是fileinputstream的子类,需要与fileinputstream结合使用
//实例化fileinputstream
FileInputStream fis = new FileInputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\text\\QQ截图20240629214809.png");
DataInputStream dis = new DataInputStream(fis);
FileOutputStream fos = new FileOutputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\Test\\text\\1.png");
// BufferedReader br = new BufferedReader(dis);
byte[] b1 = new byte[1024];
// System.out.println(dis.read(b1));
// for(byte b : b1){
// System.out.print((char)b);
// }
int len;
while((len = dis.read(b1,0,b1.length)) != -1){
fos.write(b1,0,len);
}
dis.close();
fos.close();
fis.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
练习五
需求说明实现学员对象的序列化和反序列化
package exercise05;
import java.io.*;
public class TestObjectinout {
public static void main(String[] args) {
try {
//先创建序列化流和反序列化流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\exercise05\\text.txt"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\exercise05\\text.txt"));
//创建用户实例
Student student = new Student("张三",18);
//进行序列化
oos.writeObject(student);
//实现反序列化
Student s = (Student) ois.readObject();
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}
作业
作业一
1.从键盘输入文件的路径,不存在则创建文件,存在则输出文件信息,如:文件名,字节数,内容。
最后写入文件内容在输出信息。
package homework01;
import java.io.*;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
// String path = "";
System.out.println("请输入文件路径");
//这里使用nextline的原因
// nextLine() 可以读取包括空格和特殊字符在内的整行文本,而 next() 只能读取到下一个空白字符前的字符串。
// 这意味着如果文件路径包含空格或者特殊字符,nextLine() 能够正确读取整个路径,而 next() 则不能。
String path = sc.nextLine();
File file = new File(path);
if (!file.exists()){
file.createNewFile();
System.out.println("文件已创建");
}
Reader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
System.out.println(" " + file.getName() + file.length() + br.readLine());
br.close();
fr.close();
// file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
作业二
2.手动创建文件,内容如下
name=张三,age=18,sex=女|name=李四,age=12,sex=男
利用字节流读取文件内容并保存对象到List集合中,循环打印集合
Test
package homework02;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
try {
//读取文件
Reader fr = new FileReader("G:\\鸿卓java全栈学习\\鸿卓java全栈学习代码\\java\\java 高级编程\\project04\\src\\homework02\\people.txt");
BufferedReader br = new BufferedReader(fr);
//将信息存到字符串中
String info = br.readLine();
System.out.println(info);
//创建对象集合
List<prople> l = new ArrayList<prople>();
// System.out.println(info.split("\\|"));
// l.add(info.split("\\|"));
//第一次分割,分隔开张三和李四,并用数组进行存储
String[] s = info.split("\\|");
for (String s1 : s){
//第二次分割,将各个属性分隔开
String[] ss = s1.split(",");
//第三次分割,将属性名称=与属性值分隔开,并获取值赋值给变量
String name = ss[0].split("=")[1];
int age = Integer.parseInt(ss[1].split("=")[1]);
String sex = ss[2].split("=")[1];
//创建对象并添加到集合中
l.add(new prople(name,age,sex));
}
//遍历打印
for (prople p : l){
System.out.println(p.getName()+ p.getAge()+p.getSex());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
prople
package homework02;
public class prople {
private String name;
private int age;
private String sex;
public prople(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}