IO流
文件
文件可认为是相关记录或放在一起的数据的集合。
java API:java.io.File类
File类访问文件属性
创建文件对象:
File file = new File(String pathname);
File类常用方法:
public class FileTest {
public static void main(String[] args) {
File file = new File("E:\\笔记\\test.txt");
File file1 = new File("E:\\笔记\\testshengshi.sql");
try {
file.createNewFile(); // 此方法创建一个空文件不能创建文件夹
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("文件的大小"+file1.length()+"字节");
//System.out.println("是否删除文件:"+file.delete());
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果
文件或目录是否存在true
是否为文件:true
是否为目录:false
相对路径:E:\笔记\test.txt
绝对路径:E:\笔记\test.txt
文件或目录名称:test.txt
文件的大小260579字节
流
流是指一连串流动的字符,是以先进先出的方式发送信息的通道。
java流的分类
输入输出流是相对于计算机内存来说的。
字节流是8位通用字节流,字符流是16位Unicode字符流。
文本文件的读写
InputStream类是一个抽象类,FileInputStream是其子类
FileInputStream
思路:引入相关的类–>构造文件输入流FileInputStream对象–>读取文本文件的数据–>关闭文件流对象
“E:\笔记\test.txt”事先已经存在,并且写入了内容
hello world!!!
hello world!!!
public class FileTest1 {
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream("E:\\笔记\\test.txt");
System.out.println("可以读取到的字节数:"+fis.available());
// 方法一:使用输入流read()方法
int data;
while ((data = fis.read()) != -1){
System.out.print((char)data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
}
}
结果
可以读取到的字节数:50
hello world!!!
hello world!!!
public class FileTest2 {
public static void main(String[] args) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream("E:\\笔记\\test.txt");
System.out.println("可以读取到的字节数:"+fis.available());
// 方法二:使用输入流read(byte[] b)方法,次方法效率更高
byte[] b = new byte[fis.available()];
int data1;
while ((data1 = fis.read(b)) != -1){
for (int i = 0; i < data1; i++) {
System.out.print((char)b[i]);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
}
}
结果
可以读取到的字节数:50
hello world!!!
hello world!!!
结论:
- InputStream是字节输入流,读取文件返回的是int类型的字节数长度,如果到了输入流末尾,则返回-1。
- read()和read(byte[] b)不能同时使用,除非重新构造一个输入流FileInputStream对象,就好比一个管道里的水第一次抽光了,第二次肯定就没有了。
FileReader
思路:引入相关的类–>构造FileReader对象–>调用read()方法读取数据–>关闭文件流对象
public class FileTest3 {
public static void main(String[] args) throws IOException {
FileReader fr = null;
try {
fr = new FileReader("E:\\笔记\\test.txt");
StringBuffer s = new StringBuffer();
char[] a = new char[100];
int b = -1;
while ((b = fr.read(a)) != -1){
s.append(a);
}
System.out.println(s);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
fr.close();
}
}
}
结果
hello world!!!
hello world!!!
BufferedReader
思路:引入相关的类–>构造BufferedReader对象和FileReader对象–>调用readLine()方法读取数据–>关闭文件流对象
public class FileTest4 {
public static void main(String[] args) throws IOException {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader("E:\\笔记\\test.txt");
br = new BufferedReader(fr);
String line = null; // bufferedReader是一行一行读,每一行就是字符串,用String接收
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
br.close();
fr.close();
}
}
}
结果
hello world!!!
hello world!!!
FileOutputStream
思路:引入相关的类–>构造文件输出流FileOutputStream对象–>把数据写入文本文件–>关闭文件流对象
public class FileTest5 {
public static void main(String[] args) throws IOException {
String pathName = "E:\\笔记\\test1.txt";
File file = new File(pathName);
FileOutputStream fos = null;
try {
file.createNewFile(); // 首先创建文件
System.out.println("写入之前文件的长度为:"+file.length()+"字节");
fos = new FileOutputStream(pathName);
String s = "好好学习,天天向上";
byte[] b = s.getBytes(); // 将字符串打散为一个字节数组
fos.write(b);
System.out.println("写入之后文件的长度为:"+file.length()+"字节"); // 证明写入成功
} catch (IOException e) {
e.printStackTrace();
} finally {
fos.close();
}
}
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:27字节
FileWriter
思路:引入相关的类–>构造FileWriter对象–>调用writer()方法写入相关的数据–>关闭文件流对象
public class FileTest6 {
public static void main(String[] args) throws IOException {
String pathName = "E:\\笔记\\test2.txt";
File file = new File(pathName);
FileWriter fr = null;
try {
file.createNewFile();
System.out.println("写入之前文件的长度为:"+file.length()+"字节");
fr = new FileWriter(pathName,true); // 加true的意思是在原文件内容基础上进行追加
String str = "今天是个好日子";
fr.write(str);
fr.flush(); // 清空缓存区
System.out.println("写入之后文件的长度为:"+file.length()+"字节");
} catch (IOException e) {
e.printStackTrace();
} finally {
fr.close();
}
}
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:21字节
注意:
- 如果在原文件内容的基础上添加内容,需要加参数true
- 文件写入一般都需要清空缓存区,防止文件写不出来
BufferedWriter
思路:引入相关的类–>构造BufferedWriter对象和FileWriter对象–>调用write()方法写入相关数据–>关闭文件流对象
public class FileTest7 {
public static void main(String[] args) throws IOException {
String pathName = "E:\\笔记\\test3.txt";
File file = new File(pathName);
FileWriter fw = null;
BufferedWriter bw = null;
try {
file.createNewFile();
System.out.println("写入之前文件的长度为:"+file.length()+"字节");
fw = new FileWriter(pathName,true); // 加true的意思是在原文件内容基础上进行追加
bw = new BufferedWriter(fw);
String str = "今天是元旦假期";
String str1= "是的!";
bw.write(str);
bw.newLine(); // 写文本时创建新的一行
bw.write(str1);
bw.flush(); // 清空缓冲区,防止文件写不出来
System.out.println("写入之后文件的长度为:"+file.length()+"字节");
} catch (IOException e) {
e.printStackTrace();
} finally {
bw.close();
fw.close();
}
}
}
结果
写入之前文件的长度为:0字节
写入之后文件的长度为:32字节
综合练习
public class FileTest8 {
public static void main(String[] args) throws IOException {
// 新创建一个文件"E:\\笔记\\test4.txt",往文件中写入"元旦假期我在学习""学习使我快乐",然后读取文件内容,并把它重新写到"E:\\笔记\\test5.txt"
String pathName = "E:\\笔记\\test4.txt";
String pathName1 = "E:\\笔记\\test5.txt";
File file = new File(pathName);
File file1 = new File(pathName1);
FileWriter fw = null;
BufferedWriter bw = null;
FileWriter fw1 = null;
BufferedWriter bw1 = null;
FileReader fr = null;
BufferedReader br = null;
try {
// 创建文件
file.createNewFile();
file1.createNewFile();
// 写入内容
fw = new FileWriter(pathName);
bw = new BufferedWriter(fw);
fw1 = new FileWriter(pathName1);
bw1 = new BufferedWriter(fw1);
String str1 = "元旦假期我在学习";
String str2 = "学习使我快乐";
bw.write(str1);
bw.newLine();
bw.write(str2);
bw.flush();
// 读取内容
fr = new FileReader(pathName);
br = new BufferedReader(fr);
String line = null;
while ((line=br.readLine())!=null){
System.out.println(line);
// 重新写入新文件
bw1.write(line);
bw1.newLine();
bw1.flush();
}
System.out.println("test4.txt的长度为:"+file.length()+"字节");
System.out.println("test5.txt的长度为:"+file1.length()+"字节");
} catch (IOException e) {
e.printStackTrace();
} finally {
bw1.close();
br.close();
fr.close();
fw1.close();
bw.close();
fw.close();
}
}
}
结果
元旦假期我在学习
学习使我快乐
test4.txt的长度为:44字节
test5.txt的长度为:46字节
读取文件中的内容,将部分内容进行替换
public class FileTest10 {
public static void main(String[] args) throws IOException {
// 读取"E:\\笔记\\test6.txt"内容,将里面部分内容进行替换,写入到test7.txt中
String pathName1 = "E:\\笔记\\test6.txt";
String pathName2 = "E:\\笔记\\test7.txt";
FileReader fr = null;
FileWriter fw = null;
BufferedReader br = null;
BufferedWriter bw = null;
File file = new File(pathName2);
try {
file.createNewFile();
fr = new FileReader(pathName1);
br = new BufferedReader(fr);
StringBuffer sbf = new StringBuffer(); // 使用StringBuffer进行接收
String line = null;
while ((line = br.readLine()) != null){
sbf.append(line);
}
System.out.println("替换前的内容为:"+sbf);
String newStr = sbf.toString()
.replace("{name1}","欧欧")
.replace("{type}","狗狗")
.replace("{name2}","花花");
System.out.println("替换后的内容为:"+newStr);
// 写入到新的文件
fw = new FileWriter(pathName2);
bw = new BufferedWriter(fw);
bw.write(newStr);
bw.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
bw.close();
fw.close();
br.close();
fr.close();
}
}
}
结果
替换前的内容为:我养了一条叫{name1}的{type},我想把它改名为{name2}。
替换后的内容为:我养了一条叫欧欧的狗狗,我想把它改名为花花。
读写二进制文件
使用字节流(图片,视频,音频等非文字文件)
DataInputStream
使用DataInputStream读二进制文件
思路:引入相关的类–>构造数据输入流对象–>调用read()方法读取二进制数据–>关闭数据输入流
DataOutputStream
使用DataOutputStream写二进制文件
思路:引入相关的类–>构造数据输出流对象–>调用write()方法写二进制文件的数据–>关闭数据输出流
public class FileTest9 {
public static void main(String[] args) throws IOException {
// 将"E:\picture.png" 赋复制到"E:\\笔记"文件夹下
String pathName1 = "E:\\picture.png";
String pathName2 = "E:\\笔记\\picture.png";
File file = new File(pathName2);
boolean file1 = file.isFile();
System.out.println("\"E:\\笔记\"下复制之前是否存在picture.png==>"+file1);
// 执行复制操作
FileTest9 copy = new FileTest9();
copy.copyFile(pathName1,pathName2);
boolean file2 = file.isFile();
System.out.println("\"E:\\笔记\"下复制之后是否存在picture.png==>"+file2);
}
public void copyFile(String file1, String file2) throws IOException {
FileInputStream fis = null;
DataInputStream dis = null;
FileOutputStream fos = null;
DataOutputStream dos = null;
try {
fis = new FileInputStream(file1);
dis = new DataInputStream(fis);
byte[] b = new byte[fis.available()];
while (fis.read(b)!=-1){
fos = new FileOutputStream(file2);
dos = new DataOutputStream(fos);
dos.write(b);
dos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
dos.close();
fos.close();
dis.close();
fis.close();
}
}
}
结果
"E:\笔记"下复制之前是否存在picture.png==>false
"E:\笔记"下复制之后是否存在picture.png==>true
备注:面向对象的好处是增强代码复用性,可以将读和写的做成法,以后直接调用。
序列化和反序列化
ObjectOutputStream
序列化:
思路:实现Serializable接口–>创建FileOutputStream和ObjectOutputStream对象输出流–>调用writeObject()方法–>关闭对象输出流
ObjectInputStream
反序列化:
思路:实现Serializable接口–>创建FileInputStream和ObjectInputStream对象输入流–>调用readObject()方法–>关闭对象输出流
public class Student implements Serializable { // 实现Serializable接口
private String name;
private String sex;
private int age;
private transient String pwd;// 某些信息不想被序列化,可以加transient,输出为null
public Student() {}
public Student(String name, String sex, int age, String pwd) {
this.name = name;
this.sex = sex;
this.age = age;
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
public class Application {
public static void main(String[] args) throws IOException {
String pathName = "E:\\笔记\\student.txt";
Student student = new Student("李明", "男", 18, "123456");
// 序列化
FileOutputStream fos = null;
ObjectOutputStream oos = null;
// 反序列化
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
// 序列化
fos = new FileOutputStream(pathName);
oos = new ObjectOutputStream(fos);
oos.writeObject(student);
System.out.println("序列化成功...");
// 反序列化
fis = new FileInputStream(pathName);
ois = new ObjectInputStream(fis);
Student o = (Student) ois.readObject();
System.out.println("反序列化成功...");
System.out.println("反序列化后为,姓名:"+o.getName()+"\t性别:"+o.getSex()+"\t年龄:"+o.getAge()+"\t密码:"+o.getPwd());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
ois.close();
fis.close();
oos.close();
fos.close();
}
}
}
结果
序列化成功...
反序列化成功...
反序列化后为,姓名:李明 性别:男 年龄:18 密码:null
结论:对象要序列化,必须先实现Serializable接口,某些信息不想被序列化,可以加transient,输出为null。反序列化返回的是Object类型,需要进行类型转换。