一、字节流(FileOutputStream | FileInputStream)
代码演示了,如何使用字节流对象,将内容的写入到文件中
提示:这里的写入的数据不包含中文。
1.写入数字
package FileTest;
/**
* 温馨提示:在学习io流的时候,需要file类的知识,我的博客也有文件类file的
* 使用方法,欢迎大家学习。
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* IO流的分类:(方向)输入流、输出流
* (文件类型)字节流(所有文件)、字符流(纯文本文件 )
*
*FileOutStream(抽象方法,在调用的时候需要调用子类对象FileOutputStream)
* ->操作本地文件的字节输出流,可以把程序中的数据写到文件中。
* 步骤:
* 创建实例
* 写入数据
* 释放数据
*
*三个无用的方法:
* void write(int b)->一次写一个字节数据
* void write(byte[] b)->一次写一个字节数组
* void write(byte[] b,int off,int len)->一次写一个字节数组的部分数据
*/
public class Dome11 {
public static void main(String[] args) throws IOException {
/**
* 第一种写法:(个人推荐使用第一种写法)
* 1.注意在第一个中我没有使用f1.createNewFile()方法去创建文件
* 2."D:\\a\\a.txt"这个路径的文件,我的电脑上有,你在使用时需要自己手动
* 创建该目录下的文件
*
*/
//创建文件目录
String filePath = "D:\\a\\a.txt";
//创建一个文件类
File f1 = new File(filePath);
//判断文件是否存在;如果文件不存在就会结束程序
if(!f1.exists()) return;
//创建输出流的实例对象
FileOutputStream fos1 = new FileOutputStream(f1);
//使用write写入一个字节数据
fos1.write(99);
//创建一个字节数组
byte[] bytes = {97,98,99};
//使用write方法写入一个字节数组
fos1.write(bytes);
//使用write方法写入bytes字节数组的第一个和第二个字节数据
fos1.write(bytes,0,2);
//释放实例对象,结束资源占用
fos1.close();
/**
* 第二种写法:
* 1.小细节:就是在使用new FileOutputStream(filePath)括号中
* 可以是File文件类,也可以是目录字符串
* 2.小细节:在使用FileOutputStream fos1 = new FileOutputStream(filePath);
* 时,如果filePath文件路径下的文件存在并拥有内容,在创建实例对象的时候会
* 将文件中的内容清空;
* 如果filePath文件路径下的文件不存在,在创建实例对象的时候会创建该文件
* 这两个的前提是filePath记录的父路径正确
*
* //创建文件目录
* String filePath = "D:\\a.txt";
*
* //创建输出流的实例对象
* FileOutputStream fos1 = new FileOutputStream(filePath);
*
* //使用write写入一个字节数据
* fos1.write(99);
*
* //创建一个字节数组
* byte[] bytes = {97,98,99};
*
* //使用write方法写入一个字节数组
* fos1.write(bytes);
*
* //使用write方法写入bytes字节数组的第一个和第二个字节数据
* fos1.write(bytes,0,2);
*
* //释放实例对象,结束资源占用
* fos1.close();
*/
}
}
2.写入字符串
将字符串转换为字节数组,并写入文件实现换行和追加写入功能。
package FileTest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 本示例代码实现了
* 将字符型的数据转换为byte型写入文本文件,并加入换行效果。
*/
public class Dome12 {
public static void main(String[] args) throws IOException {
//创建文件目录
String filePath = "D:\\a\\a.txt";
//创建一个文件类
File f1 = new File(filePath);
//判断文件是否存在;如果文件不存在就会结束程序
if (!f1.exists()) return;
//创建输出流的实例对象
FileOutputStream fos1 = new FileOutputStream(f1);
//创建一个字符串
String inputStr = "你好,美丽的女士";
//将字符串转化为byte数组型
byte[] bytes= inputStr.getBytes();
//输出转化后的数据
System.out.println("转化后的数据:" + bytes.toString());
//写入字节数组数据
fos1.write(bytes);
//再次创建一个字符串,并进行数据形式转换
String inputStr1 = "i love you";
byte[] inputStr1Bytes = inputStr1.getBytes();
//创建转义字符串实现写入数据换行的效果
String str = "\r\n";
byte[] strBytes = str.getBytes();
//创建输出流的实例对象fos2,在参数列表中加入了true,这样就不会清除文件
//里的内容了,实现数据的追加写入
FileOutputStream fos2 = new FileOutputStream(f1,true);
//写入实现换行效果的数据
fos2.write(strBytes);
//写入数据
fos2.write(inputStr1Bytes);
//释放实例对象,结束资源占用
fos2.close();
fos1.close();
}
}
3.实践(实现文件内容的读取和拷贝)
package FileTest;
import java.io.*;
import java.util.Date;
/**
* int read()->当文件不为空且未读到尾的时候,其返回文件中内容的acsii码
* 当读取文件内容读完后,会返回-1;
*
* fos1.write(bytes,0,len);
* bytes->需要写入的字节数据;
* 0->从字节数组中的第几位开始;
* len->一次写入的长度
*
*
* 1024*1024*1 = 1MB
* 1KB = 1024Byte
* 1MB = 1024KB
*
*/
/**
* 补充内容:
* 使用try - catch-finally 捕获异常,处理异常
* 格式:
* try{
* 代码行;
* }catch{
* 代码行;
* }finally{
* 代码行;
* }
* 快捷方式:选中自己想写入到try-catch中的代码,在状态栏上选择code(代码)
* 选择(Surround for)包围方式
*/
public class Dome13 {
public static void main(String[] args) throws IOException {
//创建输入流的文件目录
String fileInPath = "D:\\a\\a.txt";
//创建输出流的文件目录
String fileOutPath = "D:\\a\\b.txt";
//创建输入流文件类
File f1 = new File(fileInPath);
//创建输出流文件类
File f2 = new File(fileOutPath);
//创建输入流的实例对象
FileInputStream fis1 = new FileInputStream(f1);
//创建输出流的实例对象
FileOutputStream fos1 = new FileOutputStream(f2);
//创建一个int型的变量,来接收acsii码
int b;
//创建一个开始时间类
Date startDate = new Date();
//使用循环,进行遍历文件里的内容,当读取文件内容读完后,会返回-1;
while( (b = fis1.read()) != -1){
System.out.print((char)b);
}
//创建一个结束时间类
Date endDate = new Date();
//创建一个int型变量,来接受一次所读取内容的长度
int len;
//创建一个字节数据,来接受所读取的数据(接受的dui)
byte[] bytes = new byte[1024*1];
//使用循环进行文件拷贝
while((len = fis1.read(bytes)) != -1){
fos1.write(bytes,0,len);
}
//计算打印文件内容所需要的时间
long times = endDate.getTime() - startDate.getTime();
//输出所用时间
System.out.println("打印文件内容所需要的时间毫秒:" + times);
//释放实例,结束资源占用
fos1.close();
fis1.close();
}
}
4.补充内容(时间类Date)
5.编码的讲解(GBK | UTF-8)
如何使用不同编码方式对字符串进行处理
package FileTest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
*学习目标:
* 学会使用编码和解码的方法
* 编码:
* public byte[] getBytes()->使用默认方式进行编码
* public byte[] getBytes(String charsetName)->使用指定方式进行编码
* 解码:
* String (byte[] bytes)->使用默认方式进行解码
* String (byte[] bytes, String charsetName)->使用指定方式进行解码
*
*
* idea使用的默认方式是 utf-8
* 一个英文 1个字节 | 一个中文 3个字节
*
* 下面的代码我使用了链式编写,防止小白看不懂,对重要的两点进行分析
*
* 对Arrays.toString(str.getBytes())分析:
*
* 先看Str.getBytes(),使用默认编码方式
* 进行编码,返回byte[]型数据,然后使用Arrays.toString()方法将返回的数据
* 转化为字符串
*
* 对new String(str.getBytes("GBK"),"GBK")进行分析:
*
* new String(str.getBytes("GBK"),"GBK")相当与下面写的代码
*
* byte[] bytes = str.getBytes("GBK");
* String decodeStr = new String(bytes,"GBK");
*
*
*/
public class Dome15 {
public static void main(String[] args) throws UnsupportedEncodingException {
//创建一个字符串
String str = "你好美丽的女士,i love you";
//使用默认方式编码,这里使用toString()方法将结果转成字符串,输出结果
System.out.println("默认方式编码的结果:" + Arrays.toString(str.getBytes()));
//使用GBK方式进行编码,并输出结果
System.out.println("GBK方式编码的结果:"+Arrays.toString(str.getBytes("GBK")));
System.out.println("———————————————————");
System.out.println("使用默认方式编码后,使用不同的解码方式进行解码");
System.out.println("默认方式解码:" + new String(str.getBytes()));
System.out.println("GBK方式解码:" + new String(str.getBytes(),"GBK"));
System.out.println("———————————————————");
System.out.println("使用GBK方式编码后,使用不同的解码方式进行解码");
System.out.println("默认方式解码:" + new String(str.getBytes("GBK")));
System.out.println("GBK方式解码:" + new String(str.getBytes("GBK"),"GBK"));
}
}
二、字符流(FileReader | FileWriter)
有了字节流的铺垫,我这里直接进行实战演示(实现文件的拷贝)
1.实践(文件拷贝)
package FileTest;
import java.io.*;
/**
*学习目标:
* 了解字符流的两种形式 FileReader(字符输入流)、FileWriter(字符输出流)
* 学习使用字符流中的FileWriter()进行文件拷贝
*
* public FileReader(File file)->创建字符输入流关联文件类对象
* public FileReader(String pathName)->创建字符输入流关联文件路径
*
* public int read()->读取字节数据,读到尾部返回-1
* public int read(char[] buffer)->读取数据存储到buffer中,返回长度,读到尾部
* 返回-1。
*
* public FileWriter(File file)->创建字符输出流关联文件类对象
* public FileWriter(String pathName)->创建字符输出流关联文件路径
*
* public FileWriter(File file,boolean append)
* public FileWriter(String pathName,boolean append)
*File file->关联的文件类对象
* String pathName->关联的文件目录
* append->是否打开续写开关,true->打开 | false->关闭
*
*写入方法介绍:
* void write(int ch)->写入一个字符
* void write(String str)->写入一个字符串
* void write(String str, int off, int len)->写入一个字符串的一部分
* off为字符串的起始位置;len为从起始位置到结束位置的长度
*
* void write(char[] charBuffer)->写入一个字符数组
* void write(char[] charBuffer, int off, int len)->写入一个字符数组的一部分
* 参数解释与上面的一样
*
*/
public class Dome16 {
public static void main(String[] args) throws IOException {
//创建文件类路径
String filePath = "D:\\a\\c.txt";
//创建文件实例对象
File files= new File(filePath);
//创建字符输入流实例化对象
FileReader fd1 = new FileReader(files);
//创建data来接收返回的int型数据
int data;
//创建长度为5的char型的charData,一次接受来接受5的字节
char[] charData = new char[5];
//创建len来记录返回长度,读到文件尾部的时候可能不满5个字节
int len;
//使用循环一次一个字节的读取数据
while((data = fd1.read()) != -1){
System.out.print((char)data);
}
System.out.println("\n———————————————————");
/**
* 为什么不用fd1,而又创建了fd2呢?
* 原因是java的底层在进行文件读取的时候使用的是指针,当第一次读到尾的时候
* 其指针是在尾部,如果第二次继续使用fd1的话,它是从尾部开始读取数据
* 这样就会读不出任何数据;所以创建了fd2
* 在java中FileReader中无法像c语言中使用rewind ()方法,进行指针回溯。
* 在流中,想进行一次输出,就需要创建一次流对象
*/
//创建字符输入流实例化对象
FileReader fd2 = new FileReader(files);
//使用循环一次5个字节的读取数据
while((len = fd2.read(charData)) != -1){
System.out.print(new String(charData, 0, len));
}
System.out.println("\n———————————————————");
/**
* 将c.txt文件中的内容拷贝到d.txt中
* 这里我只演示void write(String str, int off, int len)
* void write(char[] charBuffer, int off, int len)
*/
//创建输出流对象,打开续写开关
FileWriter fw1 = new FileWriter(new File("D:\\a\\d.txt"),true);
//创建字符输入流实例化对象
FileReader fd3 = new FileReader(files);
//创建需要使用的变量
String str = "你好美丽的女士!\ni love you\n";
int lens;
char[] chars = new char[5];
//使用字符串型写入文件中
fw1.write(str,0,str.length()/2);
fw1.write(str,str.length()/2,str.length()/2);
//使用循环读取文件内容,并使用write()方法拷贝到d.txt中
while((lens = fd3.read(chars)) != -1){
fw1.write(chars, 0, lens);
}
System.out.println("拷贝成功");
//释放资源
fw1.close();
fd2.close();
fd1.close();
}
}
三、缓冲流
实践(字节缓冲流进行-文件拷贝)
package FileTest;
import java.io.*;
import java.text.FieldPosition;
/**
* 学习目标:
* 了解字节缓冲流中的输入流|输出流
*
* 字节缓冲流
* public BufferedInputStream(InputStream is)
* public BufferedOutputStream(InputStream os)
*/
public class Dome17 {
public static void main(String[] args) throws IOException {
//创建字节缓冲流中的输入、输出流的实例对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("D:\\a\\a.txt")));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\a\\b.txt")));
//创建len来接收数据的长度
int len;
//创建一个大小为1KB字节数组
byte[] bytes = new byte[1024];
//使用循环进行拷贝(字节拷贝)
while((len = bis.read(bytes)) != -1){
bos.write(bytes,0, len);
}
//释放资源
bos.close();
bis.close();
}
}
实践(字符缓冲流—文件拷贝)
向文件里写入回答信息并使用特定方法进行换行
package FileTest;
import java.io.*;
/**
* 学习目标:
* 了解字符缓冲流中的输入流|输出流
*
* 字符缓冲流
* public BufferedReader(Reader r)
* public BufferedWriter(Writer w)
*
* 字符缓冲流的特有方法:
* public String readLine()->读取一行数据,如果读完了,返回null
* public void newLine()->跨平台的换行
*/
public class Dome18 {
public static void main(String[] args) throws IOException {
//创建字符缓冲流中的输入、输出流的实例对象
BufferedReader br = new BufferedReader(new FileReader(new File("D:\\a\\c.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("D:\\a\\c.txt"),true));
//创建一个data来接收数据
String data;
//使用循环和readLine()方法,进行读取数据
while((data = br.readLine())!= null) {
System.out.println(data);
}
//使用write()方法写入数据,并使用newLine()方法进行换行
bw.newLine();
bw.write("女士的回答为:我接受");
bw.newLine();
bw.write("男士笑得很开心");
//提前释放资源,为了下面的输出环境
bw.close();
br.close();
System.out.println("———————————————————");
//在创建字符缓冲输入流,是为了将文件指针重置
BufferedReader brTemp = new BufferedReader(new FileReader(new File("D:\\a\\c.txt")));
//使用循环和readLine()方法,进行读取数据
while((data = brTemp.readLine())!= null) {
System.out.println(data);
}
//释放资源
brTemp.close();
}
}
四、转化流(InputStreamReader | OutputStreamWriter)
使用转化流知识点,进行文件的编码转化
package FileTest;
import java.io.*;
/**
* 学习目标:
* 了解转化流
*InputStreamReader
* OutputStreamWriter
*
* 扩展:
* 在FileReader | FileWriter中包含InputStreamReader | OutputStreamWriter
* 的解码和编码的功能;
* 例
* FileReader fr = new FileReader(New File("pathname"),Charset.forName("GBK"));
*Charset.forName("GBK")指定编码为GBK
*/
public class Dome19 {
public static void main(String[] args) throws IOException {
//创建InputStreamReader | OutputStreamWriter的实例化对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(new File("D:\\a\\a.txt")),"UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(new File("D:\\a\\e.txt")),"GBK");
//将a.txt中的文件正常读取,以GBK的编码写到d.txt文件中
int ch;
while((ch = isr.read()) != -1){
osw.write(ch);
}
//释放资源
isr.close();
osw.close();
}
}
五、序列化流和反序列化流(ObjectOutputStream | ObjectInputStream)
使用序列化知识,将一个对象序列化,并写入到文件中。
package FileTest;
import java.io.*;
/**
*学习目标:
* 了解序列化流
* 了解反序列化流
*
* 序列化:
* public ObjectOutputStream(FileOutputStream fos)->将文件输出流变成高级流
* public final void writeObject(Object obj)->将序列化的对象写到文件中
*
* 反序列化:
* public ObjectInputStream(FileInputStream fos)->将文件输入流变成高级流
* public Object readObject()->返回文件中序列化的对象
*
*
* 补充:
*需要写入文件中的类对象,需要实现Serializable接口
*
* 序列化的对象在写入文件后,如果你修改了序列化对象的成员变量等,在你反
* 序列化的 时候会有报错;
* 为了解决这个问题,你将你需要序列化的对象设置一个
* 序列号(serialVersionUID);
* 设置方法,你可以在idea中进行设置,也可以自己写一个。
* 例:
* private static final long serialVersionUID = 1L;
* 加L的原因是因为serialVersionUID是long类型的数据。
*
* 如果你想你序列化对象中的某个成员变量不被序列化,你可以使用transient
* 关键字进行标记
*
* 如果你想一次写入多个序列化对象,你可以把对象放到一个ArrayList中,在写入
* 到文件中,这样在你读取文件中的序列化对象时,你就不需要提前知道文件中
* 有多少个序列化对象。
*/
public class Dome110 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//实例化一个学生类对象
Student stu = new Student("小媚",18);
//创建高级流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\a\\e.txt")));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\a\\e.txt")));
//使用writeObject(Object obj)方法写入文件
oos.writeObject(stu);
//使用readObject()返回文件中的序列化对象,并打印出来
System.out.println(ois.readObject());
//释放资源
ois.close();
oos.close();
}
}
六、打印流
使用打印流,将数据写入文件
package FileTest;
import java.io.*;
/**
*public PrintStream(OutputStream | File | String)->关联字节输出流|文件|文件路径
* public PrintStream(String fileName, Charset charset)->指定字符编码
* public PrintStream(OutputStream out, boolean autoFlush)->自动刷新
* public PrintStream(OutputStream out, boolean autoFlush, String encoding)
* ->指定字符编码且自动刷新
*需要知道的成员方法:
* public void println()->打印任意数据,自动刷新,自动换行
* public void print()->打印任意数据,自动刷新
* public void printf()->带有占位符的打印语句,不换行【和c语言里的printf()
* 使用方法一样】
*
* 补充:
* 字节的底层没有缓冲区,开不开自动刷新都一样
*/
public class Dome111 {
public static void main(String[] args) throws IOException {
// 字节打印流的基本操作演示
FileOutputStream fos = new FileOutputStream("D:\\a\\f.txt"); // 创建一个文件输出流
PrintStream ps = new PrintStream(fos); // 创建一个字节打印流
ps.print("Hello, "); // 打印字符串
ps.println("world!"); // 打印字符串并换行
ps.printf("This is a number: %d", 42); // 打印格式化字符串
ps.close(); // 关闭打印流
// 字符打印流的基本操作演示
FileWriter fw = new FileWriter("D:\\a\\g.txt"); // 创建一个文件写入流
PrintWriter pw = new PrintWriter(fw); // 创建一个字符打印流
pw.print("Hello, "); // 打印字符串
pw.println("world!"); // 打印字符串并换行
pw.printf("This is a number: %d", 42); // 打印格式化字符串
pw.close(); // 关闭打印流
}
}
七、压缩流
实践(多级文件压缩)
package FileTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 学习目标:
* 了解压缩的方法
* 使用对应的方法实现文件的压缩 | 文件夹的压缩
*/
public class Dome112 {
public static void main(String[] args) throws IOException {
// 源路径和目标路径用于压缩
String srcPath = "D:\\a"; // 源目录
String desPath = "D:\\a.zip"; // 目标压缩文件
// 为源和目标创建文件对象
File src = new File(srcPath);
File des = new File(desPath);
// 使用目标文件初始化 ZipOutputStream
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(des));
// 调用函数执行压缩
toZip(src, zos, src.getName().toString());
// 关闭 ZipOutputStream
zos.close();
}
/**
* 递归将文件和目录压缩到 zip 存档中。
*
* @param src 要压缩的源文件或目录
* @param zos 用于写入压缩数据的 ZipOutputStream
* @param names Zip 存档内部的文件路径
*/
public static void toZip(File src, ZipOutputStream zos, String names) throws IOException {
// 获取源目录中的文件
File[] files = src.listFiles();
for (File file : files) {
if (file.isFile()) {
// 如果项目是文件,则创建 ZipEntry 并将文件数据写入 ZipOutputStream
ZipEntry zipEntry = new ZipEntry(names + "\\" + file.getName());
zos.putNextEntry(zipEntry);
FileInputStream fis = new FileInputStream(file);
int data;
while ((data = fis.read()) != -1) {
zos.write(data);
}
fis.close();
zos.closeEntry(); // 在 ZipOutputStream 中关闭当前条目
} else {
// 如果项目是目录,则递归调用 toZip 函数
toZip(file, zos, names + "\\" + file.getName());
}
}
}
}
实践(多级文件解压缩)
package FileTest; // 定义包名
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* 学习目标:
* 学习文件夹 | 文件的解压缩
*/
public class Dome113 {
public static void main(String[] args) throws IOException {
File src = new File("D:\\a.zip"); // 源ZIP文件路径
File des = new File("D:\\"); // 目标解压目录
unZip(src, des); // 调用解压方法
}
/**
* 解压ZIP文件
*
* @param src 源ZIP文件
* @param des 目标解压目录
* @throws IOException
*/
public static void unZip(File src, File des) throws IOException {
ZipInputStream zip = new ZipInputStream(new FileInputStream(src)); // 创建ZIP输入流
ZipEntry entry; // 用于表示ZIP文件中的条目
while ((entry = zip.getNextEntry()) != null) {
if (entry.isDirectory()) { // 如果是目录
File file = new File(des, entry.toString()); // 创建目录
file.mkdirs();
} else { // 如果是文件
FileOutputStream fos = new FileOutputStream(new File(des, entry.toString())); // 创建文件输出流
int data;
while ((data = zip.read()) != -1) { // 逐字节读取并写入文件
fos.write(data);
}
fos.close();
zip.closeEntry();
}
}
zip.close();
}
}