File类 三种构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package demo10;import org.junit.Test;import java.io.File;public class FileTest { @Test public void test1 () { File file = new File("D:\\hello.txt" ); System.out.println(file); File file2 = new File("D:\\java" ,"jdk" ); System.out.println(file2); File file3 = new File(file2,"jre" ); System.out.println(file3); } }
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package demo10;import org.junit.Test;import java.io.File;public class FileTest { @Test public void test2 () { File file = new File("D:\\hello.txt" ); File file2 = new File("hello.txt" ); System.out.println(file.getName()); System.out.println(file.getAbsolutePath()); System.out.println(file.getParent()); System.out.println(file.getPath()); System.out.println(file.length()); System.out.println(file.lastModified()); System.out.println("========================" ); System.out.println(file2.getName()); System.out.println(file2.getAbsolutePath()); System.out.println(file2.getParent()); System.out.println(file2.getPath()); System.out.println(file2.length()); System.out.println(file2.lastModified()); } }
hello.txt D:\hello.txt D: D:\hello.txt 12
1622378943689
hello.txt D:\Idea WorkSpace\learn\hello.txt null hello.txt 12 1622380762330
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package demo10;import org.junit.Test;import java.io.File;public class FileTest { @Test public void test2 () { File file = new File("D:\\Java" ); String[] list = file.list(); for (String s : list){ System.out.println(s); } System.out.println("========================" ); File[] listFiles = file.listFiles(); for (File f : listFiles){ System.out.println(f); } } }
bin conf COPYRIGHT include jmods legal lib
release D:\Java\bin D:\Java\conf D:\Java\COPYRIGHT D:\Java\include D:\Java\jmods D:\Java\legal D:\Java\lib D:\Java\release
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package demo10;import org.junit.Test;import java.io.File;public class FileTest { @Test public void test2 () { File file = new File("D:\\hello.txt" ); System.out.println(file.isFile()); System.out.println(file.isDirectory()); System.out.println(file.exists()); System.out.println(file.canRead()); System.out.println(file.canWrite()); System.out.println(file.isHidden()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package demo10;import org.junit.Test;import java.io.File;import java.io.IOException;public class FileTest { @Test public void test2 () throws IOException { File file = new File("hello.txt" ); System.out.println(file.exists()); System.out.println(file.createNewFile()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package demo10;import org.junit.Test;import java.io.File;import java.io.IOException;public class FileTest { @Test public void test2 () throws IOException { File file = new File("hi.txt" ); if (!file.exists()){ file.createNewFile(); System.out.println("Created!" ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package demo10;import org.junit.Test;import java.io.File;import java.io.IOException;public class FileTest { @Test public void test2 () throws IOException { File file = new File("hi.txt" ); if (!file.exists()){ file.createNewFile(); System.out.println("Created!" ); }else { file.delete(); System.out.println("Deleted!" ); } } }
IO流原理及分类
非文本比如视频、图像适合字节流,文本适合字符流。
IO流体系
FileReader读入数据 空参read方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package demo10;import java.io.File;import java.io.FileReader;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { File file = new File("hello.txt" ); FileReader fr = new FileReader(file); int data = fr.read(); System.out.println((char )data); while (data != -1 ){ System.out.print((char )data); data = fr.read(); } fr.close(); } }
改进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package demo10;import java.io.File;import java.io.FileReader;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { FileReader fr = null; File file = new File("hello.txt" ); try { fr = new FileReader(file); int data; while ((data = fr.read())!=-1 ){ System.out.print((char )data); } } catch (IOException e) { e.printStackTrace(); } finally { fr.close(); } } }
使用read重载方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package demo10;import java.io.File;import java.io.FileReader;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { FileReader fr = null; File file = new File("hello.txt" ); try { fr = new FileReader(file); char [] cbuf = new char [5 ]; int len; while ((len = fr.read(cbuf)) != -1 ) { for (int i = 0 ; i < len; i++) { System.out.print(cbuf[i]); } } } catch (IOException e) { e.printStackTrace(); } finally { fr.close(); } } }
注意我们这里的循环里是i<len
,我们下面把它改成i<cbuf.length
, 结果:可以看到cbuf在每一次读取时被一个个覆盖,而不是清空重新赋值。 这里重载的reader方法的返回值是: 或者不用for循环,用String输出,也要注意char数组的长度问题:
FileWriter写出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package demo10;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { File file = new File("Hello.txt" ); FileWriter fw = new FileWriter(file); fw.write("Hello World!" ); fw.write("Hello Java!" ); fw.close(); } }
加个换行 之前文件被覆盖了。如果源文件存在,就覆盖,如果不存在,就创建然后写出。 如果不想覆盖,就在FileWriter构造器中添加个true。 可以看到该参数为append,既追加,默认为false,所以是覆盖。
字符流不能处理图片 不能使用字符流来处理字节数据!
处理文本 最好来说:
实现图片复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package demo10;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { File src = new File("1.png" ); File dest = new File("2.png" ); FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dest); byte[] buffer = new byte[5 ]; int len; while ((len = fis.read(buffer))!=-1 ){ fos.write(buffer,0 ,len); } fis.close(); fos.close(); } }
实现了图片复制。
指定路径下文件的复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package demo10;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class IOTest { public static void main (String[] args) throws IOException { long start = System.currentTimeMillis(); copyFile("1.mp4" ,"2.mp4" ); long end = System.currentTimeMillis(); System.out.println((end - start)/1000.0 ); } public static void copyFile (String srcPath,String destPath) throws IOException { File src = new File(srcPath); File dest = new File(destPath); FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dest); byte [] buffer = new byte [5 ]; int len; while ((len = fis.read(buffer))!=-1 ){ fos.write(buffer,0 ,len); } fis.close(); fos.close(); } }
7.635
复制一个21s的mp4文件花了7.635s。
将buffer数组改为100大小
0.607
缓冲流字节型实现非文本文件复制 作用:提高流的读取和写入的速度。 注意到缓冲流是处理流,也就是要作用到节点流,所以要先来一个节点流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package demo10;import java.io.*;public class BufferTest { public static void main (String[] args) throws IOException { File src = new File("1.png" ); File dest = new File("2.png" ); FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dest); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); byte [] b = new byte [1024 ]; int len; while ((len = bis.read(b))!=-1 ){ bos.write(b,0 ,len); } bis.close(); bos.close(); } }
缓冲流与节点流速度对比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package demo10;import java.io.*;public class BufferTest { public static void main (String[] args) throws IOException { long start = System.currentTimeMillis(); File src = new File("1.mp4" ); File dest = new File("2.mp4" ); FileInputStream fis = new FileInputStream(src); FileOutputStream fos = new FileOutputStream(dest); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); byte [] b = new byte [1024 ]; int len; while ((len = bis.read(b))!=-1 ){ bos.write(b,0 ,len); } bis.close(); bos.close(); long end = System.currentTimeMillis(); System.out.println(end - start); } }
24
而之前的节点流是0.607s也就是607ms,是将近30倍,这里我们用的都是1024大小的byte数组。
提高读写速度的原因:内部提供了一个缓冲区。
缓冲流对文本文件的复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package demo10;import java.io.*;public class BufferTest { public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt" ))); BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hi.txt" ))); char [] c = new char [1024 ]; int len; while ((len = br.read(c)) != -1 ){ bw.write(c,0 ,len); } br.close(); bw.close(); } }
上述方式仍然使用char[]数组 方式二:使用String和BufferedReader里的readLine()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package demo10;import java.io.*;public class BufferTest { public static void main (String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt" ))); BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hi.txt" ))); String data; while ((data = br.readLine()) != null ){ bw.write(data); } br.close(); bw.close(); } }
所以这里要加一个换行符 或者调用newLine()
方法
总结 此外,处理流中还有flush方法,调用它可以把缓冲区的内容写出去,只不过缓冲流自动调用它,所以在这里不用管
处理流之二 转换流 字节输入流转换为字符输入流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package demo10;import java.io.*;public class TransferTest { public static void main (String[] args) throws IOException { FileInputStream fis = new FileInputStream("hello.txt" ); InputStreamReader isr = new InputStreamReader(fis,"UTF-8" ); char [] c = new char [1024 ]; int len; while ((len = isr.read(c))!=-1 ){ System.out.println(new String(c,0 ,len)); } isr.close(); } }
这里我们如果用gbk去解码,肯定不对,会出现乱码。
综合使用转换流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package demo10;import java.io.*;public class TransferTest { public static void main (String[] args) throws IOException { File f1 = new File("hello.txt" ); File f2 = new File("hello_gbk.txt" ); FileInputStream fis = new FileInputStream(f1); FileOutputStream fos = new FileOutputStream(f2); InputStreamReader isr = new InputStreamReader(fis,"UTF-8" ); OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK" ); char [] c = new char [1024 ]; int len; while ((len = isr.read(c)) != -1 ){ osw.write(c,0 ,len); } isr.close(); osw.close(); } }
我们字节流输入,被字节转字符包住,用字符数组接收,在用OutputStreamWriter字符转字节包住的字节流输出出去,并且输出为gbk编码字符集编码的文本。
字符集
标准输入输出流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package demo10;import java.io.*;public class TransferTest { public static void main (String[] args) throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); while (true ){ System.out.print("请输入字符串:" ); String data = br.readLine(); if ("e" .equalsIgnoreCase(data)||"exit" .equalsIgnoreCase(data)){ System.out.println("程序结束" ); break ; } String s = data.toUpperCase(); System.out.println(s); } br.close(); } }
System.in是字节流,所以有些情况需要转换。
打印流
数据流
对象流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package demo10;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;public class ObjectStream { public static void main (String[] args) { ObjectOutputStream oos = null ; try { oos = new ObjectOutputStream(new FileOutputStream("object.txt" )); oos.writeObject(new String("I love java" )); oos.flush(); } catch (IOException e) { e.printStackTrace(); }finally { if (oos != null ) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
这个文件不是用来双击打开看的,就是把序列化的对象持久的保存在磁盘上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package demo10;import java.io.*;public class ObjectStream { public static void main (String[] args) { ObjectInputStream ois = null ; try { ois = new ObjectInputStream(new FileInputStream("object.txt" )); Object o = ois.readObject(); String str = (String) o; System.out.println(str); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (ois != null ){ try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
这个操作就反序列化了,将磁盘文件中的对象还原为内存中的java对象。
自定义类实现序列化和反序列化 标识接口 Serializable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package demo10;import java.io.Serializable;public class Person implements Serializable { public static final long serialVersionUID = 475463534532L ; private String name; private int age; public Person (String name, int age) { this .name = name; this .age = age; } public void setName (String name) { this .name = name; } public void setAge (int age) { this .age = age; } public String getName () { return name; } public int getAge () { return age; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package demo10;import java.io.*;public class ObjectStream { public static void main (String[] args) { ObjectOutputStream oos = null ; try { oos = new ObjectOutputStream(new FileOutputStream("object.txt" )); oos.writeObject(new String("I love java" )); oos.flush(); oos.writeObject(new Person("Hawkeye" ,20 )); oos.flush(); } catch (IOException e) { e.printStackTrace(); }finally { if (oos != null ) { try { oos.close(); } catch (IOException e) { e.printStackTrace(); } } } ObjectInputStream ois = null ; try { ois = new ObjectInputStream(new FileInputStream("object.txt" )); Object o = ois.readObject(); String str = (String) o; Person p = (Person) ois.readObject(); System.out.println(str); System.out.println(p); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (ois != null ){ try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
serialVersionUID的理解 如果我们对一个带UID的Person类序列化,那么进行一些操作比如添加一个属性id,重写toString,反序列化读回来的仍然是那个Person而且id为默认值0,如果我们对一个不带UID的Person类序列化,再执行上述操作,会报异常。简而言之:一个对象,作为序列化的二进制流,如果没有UID,它的类改变了,就还原不回来了。
其他要求
所有属性都需要可序列化 。
transient关键字 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化 。然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
static修饰的属性不能被序列化 随机存取文件流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package demo10;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class RandomTest { public static void main (String[] args) { RandomAccessFile raf = null ; RandomAccessFile raf2 = null ; try { raf = new RandomAccessFile(new File("1.png" ), "r" ); raf2 = new RandomAccessFile(new File("11.png" ), "rw" ); byte [] buffer = new byte [1024 ]; int len; while ((len = raf.read(buffer)) != -1 ) { raf2.write(buffer, 0 , len); } } catch (IOException e) { e.printStackTrace(); } finally { if (raf != null && raf2 != null ) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } try { raf2.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
发现可以完成文件的复制。 下面我们新建一个1.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package demo10;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class RandomTest { public static void main (String[] args) { RandomAccessFile raf = null ; try { raf = new RandomAccessFile(new File("1.txt" ), "rw" ); raf.write("xyz" .getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (raf != null ) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
结果如果本文件存在,则不是对文件直接覆盖,而是从源文件开头一个个覆盖,这里表现为xyz覆盖abc,按内容长度覆盖。
RandomAccessFile实现对数据插入 seek方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package demo10;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class RandomTest { public static void main (String[] args) { RandomAccessFile raf = null ; try { raf = new RandomAccessFile(new File("1.txt" ), "rw" ); raf.seek(3 ); raf.write("xyz" .getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (raf != null ) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
从3开始往后覆盖。
下面实现插入 更改1.txt如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package demo10;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class RandomTest { public static void main (String[] args) { RandomAccessFile raf = null ; try { raf = new RandomAccessFile(new File("1.txt" ), "rw" ); raf.seek(3 ); StringBuilder sb = new StringBuilder((int ) new File("1.txt" ).length()); byte [] buffer = new byte [20 ]; int len; while ((len = raf.read(buffer))!=-1 ){ sb.append(new String(buffer,0 ,len)); } raf.seek(3 ); raf.write("xyz" .getBytes()); raf.write(sb.toString().getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (raf != null ) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
实现了从第三个插入xyz