目录
- 友情提醒
- 第一章、File类和IO技术概述
- 1.1)File类和IO技术的作用
- 1.2)创建File类对象
- 1.3)File类中的方法
- 1.4)文件过滤器:FileFileter
- 第二章、IO流
- 2.1)IO流的分类
- 2.2)字节输入流:InputStream
- 2.2.1)操作文件的字节输入流:FileInputStream
- 2.2.2)字节缓冲输入流:BufferedInputStream(高效)
- 2.3)字节输出流:OutputStream
- 2.3.1) 操作文件的字节输出流:FileOutputStream
- 2.3.2)字节缓冲输出流:BufferedOutputStream(高效)
- 2.3.3)字节打印流:PrintStream
- 2.4)字符输入流:Reader
- 2.4.1)操作文件的字符输入流:FileReader
- 2.5)字符输出流:Writer
- 2.5.1)操作文件的字符输出流:FileWriter
- 2.5.2)字符打印流:PrintWriter
- 第三章、转换流
- 3.1)字符编码表
- 3.2)字符流通向字节流:OutputStreamWriter(编码)
- 3.3)字节流通向字符流:InputStreamReader(解码)
- 第四章、序列化流与反序列化流
- 4.1)对象序列化流:ObjectOutputStream
- 4.2)对象反序列化流:ObjectInputStream
- 4.3)序列化接口Serializable与瞬态关键字transient
- 第五章、IO流案例
- 5.1)复制单个文件
- 5.2)使用缓冲字节流复制单个文件(高效)
- 5.3)缓冲字节流复制当前目录下所有文件·
- 5.4)切割文件/合并文件
友情提醒
先看文章目录,大致了解知识点结构,直接点击文章目录可以跳转到文章指定位置。
第一章、File类和IO技术概述
1.1)File类和IO技术的作用
1.File类
①File类简介:Java把现实存在的文件和目录路径名描述成一个File类类。
②File类只是对持久设备上的文件和文件夹进行操作。不能去操作文件中的数据。要操作数据需要使用IO技术。
2.IO技术
①IO技术专门来实现数据与持久设备(持久保存数据的设备。硬盘、U盘等)间的交互。
②主要功能:程序中的数据可以保存到持久设备中,或者从持久设备中把数据读取到我们的Java程序中。
③I:Input:输入或者读取,持久设备数据输入到内存中。
O:Output:输出或者写出,内存中的数据输出到持久设备。
1.2)创建File类对象
①public File(String pathname) 根据文件或文件夹的路径名创建一个File对象。
②public File(String parent,String child) 根据父目录的路径名和子文件名创建一个File对象。
③public File(File parent,String child) 根据父目录的File对象和子文件名创建一个File对象。
public static void test1(){
//通过构造方法实例化File对象,jvm不会去验证参数位置定义的路径资源是否真实存在;
File f1 = new File("E\\2023Java\\Test\\file.txt");
File f2 = new File("E\\2023Java\\Test", "test1.txt");
File f3 = new File("E\\2023Java\\Test");
File f4 = new File(f3, "test2.txt");
File f5 = new File("1.txt");
System.out.println(f1);//E\2023Java\Test\file.txt
System.out.println(f2);//E\2023Java\Test\test1.txt
System.out.println(f3);//E\2023Java\Test
System.out.println(f4);//E\2023Java\Test\test2.txt
System.out.println(f5);//1.txt
}
1.3)File类中的方法
①get方法
public static void test2(){
File f1 = new File("hello\\2.txt");
//String getName():获取最后一个路径名字或者文件名字的字符串
//String getPath():获取路径名字字符串
System.out.println(f1.getName());//2.txt
System.out.println(f1.getPath());//hello\2.txt
//String getAbsolutePath():获取绝对路径名字符串。
//File getAbsoluteFile():获取绝对路径名形式。
System.out.println(f1.getAbsolutePath());//E:\javase\hello\2.txt
System.out.println(f1.getAbsoluteFile()); //E:\javase\hello\2.txt
//String getParent():返回父目录的路径名字符串;如果没有指定父目录,则返回 null。
//File getParentFile():返回父目录的路径名形式;如果没有指定父目录,则返回 null。
System.out.println(f1.getParent());//hello
System.out.println(f1.getParentFile());//hello
}
②创建文件夹和文件的方法
public static void test3(){
//创建目录:boolean mkdir():当不存在具有此抽象路径名时,创建此抽象路径名指定的目录
//在E盘下创建test目录
File f1 = new File("E:\\test");
boolean b = f1.mkdir();
System.out.println(b);
//boolean mkdirs():当不存在具有此抽象路径名时,创建此抽象路径名指定的目录,包括所有的父目录。
//在E盘下创建test\\bbb\\ccc目录
File f2 = new File("E:\\test1\\aaa\\bbb");
boolean b1 = f2.mkdirs();
System.out.println(b1);
System.out.println("**************************");
//创建文件:boolean createNewFile():当不存在具有此抽象路径名指定名称的文件时,创建
//在E:\test下创建woshisb.txt文件
try {
File f3 = new File("E:\\test\\woshisb.txt");
boolean b2 = f3.createNewFile();
System.out.println(b2);
} catch (IOException e) {
e.printStackTrace();
}
}
③删除文件和文件夹
delete方法可以删除目录,也可以删除文件
这种删除不会进回收站
public static void test4(){
//因为test文件夹里有文件woshisb.txt,所以删除失败
File f1 = new File("E:\\test");
boolean b1 = f1.delete();
System.out.println(b1);
//delete方法不支持多层级同时删除,所以只删除了bbb文件夹
File f2 = new File("E:\\test1\\aaa\\bbb");
boolean b2 = f2.delete();
System.out.println(b2);
//因为不存在所以无法删除,返回false
File f3 = new File("E:\\aaa");
boolean b3 = f3.delete();
System.out.println(b3);//false
}
④判断是否是文件/路径
public static void test5() {
/*判断
boolean isAbsolute():测试此抽象路径名是否为绝对路径名。
boolean isDirectory():测试此抽象路径名表示的文件是否是一个目录。
boolean isFile():测试此抽象路径名表示的文件是否是一个标准文件。
boolean isHidden():测试此抽象路径名指定的文件是否是一个隐藏文件。
boolean exists():测试此抽象路径名表示的文件或目录是否存在。 */
// File f = new File("E:\\woshisb.txt");
File f = new File("E:\\test");
System.out.println(f.isAbsolute());
System.out.println(f.isDirectory());
System.out.println(f.isFile());
System.out.println(f.isHidden());
System.out.println(f.exists());
}
⑤列举文件和目录
public static void test6() {
//String[] list():返回一个字符串数组,表示的目录中的文件和目录。
File file = new File("E:\\test");
String[] strs = file.list();
for (String str : strs) {
System.out.println(str);
}
System.out.println("******************************");
//File[] listFiles():返回一个抽象路径名数组,表示目录和其中的文件。
File[] files = file.listFiles();
for (File f : files) {
System.out.println(f);
}
}
1.4)文件过滤器:FileFileter
①作用:过滤我们不需要的文件,File[] listFiles(FileFilter filter) 返回符合过滤器条件的元素组成的数组。
②自定义文件过滤器类,实现FileFilter 接口,重写accept方法,并定义过滤规则
③调用listFiles方法的时候,会把每个元素都拿来调用accept方法,符合就返回true添加到数组中,否则返回false不添加到数组;
public class MyFilter2 implements FileFilter {
private String suffix;
public MyFilter2(String suffix) { this.suffix = suffix; }
public MyFilter2() { }
public String getSuffix() { return suffix; }
public void setSuffix(String suffix) { this.suffix = suffix; }
@Override
public boolean accept(File file) {
System.out.println("过滤器是文件并以.xxx结尾就不过滤,xxx自己决定");
boolean b1 = file.isFile();
boolean b2 = file.toString().endsWith(suffix);
return b1 && b2;
}
}
测试文件过滤器
public class TestFileFilter {
public static void main(String[] args) {
test1(); }
public static void test1() {
//得到E:\\test下所有.xxx结尾的文件,xxx自己决定
File file = new File("E:\\test");
//1、得到所有.txt结尾的文件,展示
MyFilter2 myFilter2 = new MyFilter2(".txt");
File[] files = file.listFiles(myFilter);
for (File f : files) {
System.out.println(f);
/*过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
过滤器是文件并以.xxx结尾就不过滤,xxx自己决定
E:\test\2.txt
*/
}
}
第二章、IO流
2.1)IO流的分类
①数据传输过程中,一切数据的传输始终为二进制数据,最后存储形式都是字节(二进制数字)。
②字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,一个字节存储8位无符号数(即1字节=8bit),储存的数值范围为0-255。(255用二进制表示 = 11111111)
③IO流的分类:IO流体系脑图链接
2.2)字节输入流:InputStream
①InputStream抽象类,是表示输入字节流所有类的超类。他们操作的数据都是字节,定义了输入字节流的基本共性功能方法
2.2.1)操作文件的字节输入流:FileInputStream
①读取文件中的数据时,调用read方法,实现从文件一次只能读取一个字节数据。
public static void test1() throws IOException {
//创建File对象,关联目标资源(文件)
File file = new File("E:\\IO\\in.txt");
//创建FileInputStream对象,绑定File对象
FileInputStream fis = new FileInputStream(file);
//每次读取一个字节内容
int num = fis.read();
System.out.println(num);
System.out.println((char) num);
num = fis.read();
System.out.println(num);
System.out.println((char) num);
num = fis.read();
System.out.println(num);
System.out.println((char) num);
num = fis.read();
System.out.println(num);
System.out.println((char) num);
fis.close();
}
//--------------------------分割----------------------------------
//使用循环读取数据
public static void test2() throws IOException {
//创建File对象,关联目标资源(文件)
File file = new File("E:\\IO\\in.txt");
//创建FileInputStream对象,绑定File对象
FileInputStream fis = new FileInputStream(file);
//每次读取一个字节内容,使用循环来实现
int num;
while (true){
if ((num=fis.read())==-1){
break;
}
System.out.println((char)num);
}
fis.close();
②读取文件中的数据时,调用read的重载方法read(byte [ ])方法,实现从文件中一次读取多个字节数据到byte[]数组内部
,减少和磁盘文件的交互次数,效率高。
文件内容是abcdefg
public static void test3() throws IOException {
//创建File对象,关联目标资源(文件)
File file = new File("E:\\IO\\in.txt");//文件内容是abcdefg
//创建FileInputStream对象,绑定File对象
FileInputStream fis = new FileInputStream(file);
//一次读取多个字节到byte[]数组内部,减少和磁盘文件的交互次数,效率高
byte[] bs = new byte[5];
//int read(byte[] bs):返回值是读取到的有效字节数5
int len = fis.read(bs);
System.out.println(len); //这次read方法执行,得到的有效字节数为5
System.out.println(new String(bs)); //内容为"abcde"
System.out.println("=========================");
// len = fis.read(bs);
// System.out.println(len); //这次read方法执行,得到的有效字节数为2
// System.out.println(new String(bs)); //"fgcde"将bs数组所有元素都转为String会存在上次读取内容
// 把上面的注释了换一个String的构造方法:String(byte[] bytes, int offset, int length),从
len = fis.read(bs);
System.out.println(len); //2
//从0下标开始将后面len个字节转为string,这样就没重复内容
System.out.println(new String(bs,0,len));//fg
fis.close();
}
③综合上述的代码,写最终版大招
public static void test4() throws IOException {
//创建File对象,关联目标资源(文件)
File file = new File("E:\\IO\\in.txt");
//创建FileInputStream对象,绑定File对象
FileInputStream fis = new FileInputStream(file);
//一次读取1024字节内容到byte[]内部,之后进行读操作
byte[] bs = new byte[1024];
int len; //用于记录读取到的有效字节数,读到文件末尾则返回-1
while ((len = fis.read(bs)) != -1) {
//从0下标开始将后面len个字节转为string,这样就没重复内容
System.out.println(new String(bs,0,len));
}
fis.close();
}
2.2.2)字节缓冲输入流:BufferedInputStream(高效)
①读取流中的数据,内部包含了一个缓冲区,通过缓冲区读写,提高了IO流的读写速度
②构造方法public BufferedInputStream(InputStream in)
private static void read() throws IOException {
//1,创建缓冲流对象
FileInputStream fileIn = new FileInputStream("abc.txt");
//把基本的流包装成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//定义一个缓冲区
byte[] buf = new byte[1024];
//2,读数据
int len = 0;
while ( (ch = in.read(buf)) != -1 ) {
//打印
System.out.print(new String(buf, 0, len));
}
//3,关闭
in.close();
}
2.3)字节输出流:OutputStream
①OutputStream抽象类是表示输出字节流所有类的超类。他们操作的数据都是字节,定义了输出字节流的基本共性功能方法
2.3.1) 操作文件的字节输出流:FileOutputStream
①输出流的覆盖模式:没文件会在目录下创建一个文件,有文件会覆盖内容
public static void test1() throws IOException {
//创建文件字节输出流对象,关联File资源(定位文件位置)
//E盘下没这个文件会在目录下创建一个文件,有文件会覆盖内容
FileOutputStream fos = new FileOutputStream(new File("E:\\out666.txt"));
fos.write(97);//a
fos.write(98);//b
fos.write(99);//c
//\r是回车符,\n是换行符
fos.write("\n\r加油".getBytes());//加油
fos.close();
}
②输出流的追加模式:没文件会在目录下创建一个文件,有追加模式不会覆盖原文件内容而是追加内容。
public static void test2() throws IOException {
//创建文件字节输出流对象,关联File资源(定位文件位置),
// 并且开启追加模式,追加模式不会覆盖原文件内容
FileOutputStream fos = new FileOutputStream(new File("E:\\out2.txt"), true);
fos.write("发福。\r\n".getBytes());
fos.write("变胖。\r\n".getBytes());
fos.close();
}
2.3.2)字节缓冲输出流:BufferedOutputStream(高效)
①写入数据到流中,内部包含了一个缓冲区,通过缓冲区读写,提高了IO流的读写速度
②构造方法public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流。
public class BufferedOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
write();
}
private static void write() throws IOException {
//创建基本的字节输出流
FileOutputStream fileOut = new FileOutputStream("abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//2,写数据
out.write("hello".getBytes());
//3,关闭流
out.close();
}
}
2.3.3)字节打印流:PrintStream
2.4)字符输入流:Reader
①使用字节流去读取文本文件可能由于编码问题,每个中文所占用的字节数不同。如:gbk下的中文2字节,utf-8下的中文占用3字节。
②字符流只能操作字符,无法操作其他数据,如声音、视频
2.4.1)操作文件的字符输入流:FileReader
FileReader类自身没有方法,使用的都是父类中的方法。
public static void test() throws IOException {
//创建文件字符输入流对象,关联数据源
FileReader fr = new FileReader("io.txt");
char[] cs = new char[4];
int len; //记录读取到的有效字符数
while ((len = fr.read(cs)) != -1) {
System.out.println(new String(cs,0,len));
}
fr.close();
}
2.5)字符输出流:Writer
2.5.1)操作文件的字符输出流:FileWriter
FileWriter类自身没有方法,使用的都是父类中的方法。
①覆盖原文件内容
public static void test1() throws IOException {
//创建文件字符输出流对象,绑定数据目的
FileWriter fw = new FileWriter("out.txt");
fw.write("自己好,");
fw.write("\r\n不是真的好!");
// fw.flush();
fw.close();
}
②不覆盖原文件内容,追加数据
public static void test2() throws IOException {
//创建文件字符输出流对象,绑定数据目的
FileWriter fw = new FileWriter("out.txt", true);
Scanner input = new Scanner(System.in);
for (int i = 1;i <= 3;i++) {
System.out.println("请输入一串数据:");
String content = input.next();
fw.write(content + "\r\n");
fw.flush();
}
fw.close();
}
2.5.2)字符打印流:PrintWriter
第三章、转换流
3.1)字符编码表
①字符编码表:就是现实中的字符数据和计算机二进制的对应关系表。
②编码:字符—>(数字),解码:(数字)—>文字
③常用的编码表:
ASCII表
1、英文字符、数字与二进制数据的一一对应关系
2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数
字,所以一共最多对应256个字符。
GBK表
1、中文字符、英文字符、数字与二进制数的 一一对应关系
2、一个英文字符对应1Bytes
一个中文字符对应2Bytes
2Bytes=16bit,16bit最多包含65536个数字,一共对应65536个字符
unicode表
国际标准码表:无论是什么文字,都用两个字节存储。
3.2)字符流通向字节流:OutputStreamWriter(编码)
OutputStreamWriter流可使用指定的字符编码表,将要写入流中的字符按照指定的编码表转成字节,在使用字节流将这些字节写出去。
public static void test2() throws IOException {
// 指定设置为utf-8的字符编码表
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out6.txt"),"utf8");
//指定设置为gbk编码的字符编码表
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out6.txt"),"gbk");
osw.write("今天要下雨!\r\n");
osw.write("大家带伞了吗?\r\n");
osw.close();
}
public static void test1() throws IOException {
//使用平台默认字符编码表
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("out5.txt"));
osw.write("今天要下雨!\r\n");
osw.write("大家带伞了吗?\r\n");
osw.close();
}
3.3)字节流通向字符流:InputStreamReader(解码)
InputStreamReader:使用指定的字符编码表读取字节并将其解码为字符。
在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。
public static void test2() throws IOException {
//FileInputStream放入InputStreamReader使用gbk编码表解码为字符
再放入BufferedReader使用readLine方法
BufferedReader br = new BufferedReader(new InputStre
amReader(new FileInputStream("E:\\IO\\change\\change.txt"), "gbk"));
String line = br.readLine();
System.out.println(line);
br.close();
}
public static void test1() throws IOException {
//使用默认的编码表解码为字符
FileReader fr = new FileReader(new File("E:\\IO\\change\\change.txt"));
char[] cs = new char[10];
int len;
while ((len = fr.read(cs)) != -1) {
System.out.println(new String(cs,0,len));
}
fr.close();
}
第四章、序列化流与反序列化流
4.1)对象序列化流:ObjectOutputStream
4.2)对象反序列化流:ObjectInputStream
4.3)序列化接口Serializable与瞬态关键字transient
第五章、IO流案例
5.1)复制单个文件
将文件中的内容读取输入到程序,再从程序输出到另一个同名文件
①复制单个文件:
//copy任意的文件
public static void copyFile2(String src, String dest) throws IOException {
long start = System.currentTimeMillis();
//创建文件字节输入、输出流,分别绑定数据源和数据目的
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
byte[] bs = new byte[1024];
int len;
while ((len = fis.read(bs)) != -1) {
fos.write(bs, 0, len);
}
//后开启的先关闭
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
5.2)使用缓冲字节流复制单个文件(高效)
①复制单个文件
public static void copyFile3(String src, String dest) throws IOException {
long start = System.currentTimeMillis();
//创建节点流(文件字节输入、输出流),分别绑定数据源和数据目的
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest);
//创建处理流(缓冲字节输入、输出流),分别绑定节点流对象
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] bs = new byte[1024];
int len;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
//关闭处理流的过程中,会自动触发关闭所包含的节点流
bos.close();
bis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
5.3)缓冲字节流复制当前目录下所有文件·
①复制当前目录层级下所有文件
/*①判断目标目录是否存在,如果不存在就立即创建
②得到src资源下所有的内容(文件、目录) ==> File[] listFile()
③遍历File数组元素,判断是否文件 ==> boolean isFile()
④在遍历的过程中发现是文件,则将文件进行copy操作,copy后的文件的名字和源文件名字保持一致
提示:获取源文件名字的方法 ==> String getName()*/
public class CopyFile{
public static void main(String[] args) throws IOException {
copyFile(new File("E:\\IO\\image"), new File("E:\\IO\\copy"));
}
public static void copyFile(File src,File dest) throws IOException {
//判断目标目录dest是否真实存在
if (!dest.isDirectory()) {
//说明不存在,直接创建
dest.mkdir();
}
//得到src资源下所有的内容(文件、目录)
File[] files = src.listFiles();
//遍历数组元素
for (File file : files) {
//判断是否是文件
if (file.isFile()) {
//说明是文件,进行复制操作,获得文件的名字
String name = file.getName();
//获得文件的绝对路径
String path = file.getAbsolutePath();
//创建FileInputStream对象,根据path绑定(目标资源),把FileInputStream对象放入BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
//FileOutputStream对象,根据dest和name绑定目标资源,把FileOutputStream对象放入BufferedOutputStream
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(dest, name)));
byte[] bs = new byte[1024];
int len;
while ((len = bis.read(bs)) != - 1) {
bos.write(bs, 0, len);
}
bos.close();
bis.close();
}
}
}
}
5.4)切割文件/合并文件
①切割文件
public class TestCut {
public static void main(String[] args) throws IOException {
//创建输入流对象,关联绑定需要被切割文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\IO\\image\\3.avi"));
//5M大小切割
byte[] bs = new byte[1024 * 1024 * 5];
int len;
int name = 1; //用于给碎片文件起名字
while ((len = bis.read(bs)) != -1) {
//创建输出流对象,关联绑定当前的碎片文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\io\\cut\\" + name + ".avi"));
bos.write(bs, 0, len);
bos.close();
name++;
}
bis.close();
}
}
②合并文件
public class TestMerge {
public static void main(String[] args) throws IOException {
//创建输出流对象,绑定需要被合并成的文件,没有这个文件会直接创建
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\IO\\merge\\合并.avi"));
byte[] bs = new byte[1024];
int len;
for (int i = 1;i <= 11;i++) {
//创建输入流对象,绑定当前的碎片文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\io\\cut\\" + i + ".avi"));
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
bis.close();
}
bos.close();
}
}