IO流的作用:持久化到磁盘
FileInputStream fileInputStream = new FileInputStream(new File("hello.tex"));
注意:文件夹和文件如果在磁盘中都没有的话,要分开分别创建文件夹和文件。
public class FileTest { /** * 文件创建的字符串参数意义 * @throws FileNotFoundException */ @Test public void test1() throws FileNotFoundException { //windows环境下用\\来作为文件夹分隔符,之所以用\\是因为\是转义符的意思,所有\\表示不转义 File fileA1 = new File("F:\\newwork\\roy-practice-metaverse\\hello-io.txt"); //windows环境下也可以像linux环境一样用/表示 File fileA2 = new File("F:/newwork/roy-practice-metaverse/hello-io.txt"); //Java提供了File.pathSeparator来拼接路径分隔符,用于读取不同的系统的路径分隔符 File fileA3 = new File("F:" + File.pathSeparator + "newwork" + File.pathSeparator + "roy-practice-metaverse" + File.pathSeparator + "hello-io.txt"); //相当于当前module模块下的hello-io.txt,如果是main方法则是当前工程下的hello-io.txt File fileR = new File("hello-io.txt"); } /** * 文件创建的3种构造器 * @throws FileNotFoundException */ @Test public void test2() throws FileNotFoundException { //构造器1:File(String pathname) File file1 = new File("F:/newwork/roy-practice-metaverse/hello-io.txt"); //构造器2:File(String parent, String child) //child可以是文件或文件夹名称 File file2 = new File("F:/newwork","roy-practice-metaverse"); //构造器3:File(File parent, String child) //child可以是文件或文件夹名称 File file3 = new File(file2,"hello-io.txt"); } }
注意:File类中的查看方法操作不会因为文件或文件夹不存在而报错,因为还都是内存层面的操作,没有涉及磁盘文件。
/** * File类的常用方法 * @throws FileNotFoundException */ @Test public void test3() throws FileNotFoundException { File file1 = new File("hi-io.txt");//文件存在的情况 System.out.println(file1.getAbsolutePath()); System.out.println(file1.getPath()); System.out.println(file1.getName()); System.out.println(file1.getParent()); System.out.println(file1.length());//默认值0 System.out.println(file1.lastModified());//默认值0 System.out.println("------------------------------------"); File file2 = new File("F:/newwork/roy-practice-metaverse/hello-io.txt"); System.out.println(file2.getAbsolutePath()); //这个path的返回值就是我们创建file对象时传入的参数,参数是绝对路径就返回绝对路径,否则就是相对路径名 System.out.println(file2.getPath()); System.out.println(file2.getName()); System.out.println(file2.getParent()); System.out.println(file2.length()); System.out.println(file2.lastModified()); } /** * F:\newwork\roy-practice-metaverse\hi-io.txt * hi-io.txt * hi-io.txt * null * 0 * 0 * ------------------------------------ * F:\newwork\roy-practice-metaverse\hello-io.txt * F:\newwork\roy-practice-metaverse\hello-io.txt * hello-io.txt * F:\newwork\roy-practice-metaverse * 0 * 0 */ /** * File类的常用方法-文件夹方法 * @throws FileNotFoundException */ @Test public void test4() throws FileNotFoundException { //文件夹遍历时该文件夹必须存在,否则NPE File file1 = new File("F:/newwork/roy-practice-metaverse"); String[] list = file1.list(); for (String name : list) { System.out.println(name); } File[] files = file1.listFiles(); for (File file : files) { System.out.println(file); } //移动文件或者重命名,要保证操作成功,需要 from在磁盘存在,而to不能存在这两个条件 File from = new File("hello-io.txt"); File to = new File("new-io.txt"); boolean success = from.renameTo(to); System.out.println(success); } /** * .idea * hello-io.txt * pom.xml * src * target * F:\newwork\roy-practice-metaverse\.idea * F:\newwork\roy-practice-metaverse\hello-io.txt * F:\newwork\roy-practice-metaverse\pom.xml * F:\newwork\roy-practice-metaverse\src * F:\newwork\roy-practice-metaverse\target * true * * * Process finished with exit code 0 */
/** * File类的判断功能 * * @throws FileNotFoundException */ @Test public void test5() throws FileNotFoundException { File existFile = new File("new-io.txt"); System.out.println(existFile.isDirectory()); System.out.println(existFile.isFile()); System.out.println(existFile.exists()); System.out.println(existFile.canRead()); System.out.println(existFile.canWrite()); System.out.println(existFile.isHidden()); System.out.println("------------------------"); File notExistFile = new File("notExist-new-io.txt"); //当文件不存在的时候,结果是既不是文件夹也不是文件,所有如果有需要可以先判断是否存在 System.out.println(notExistFile.isDirectory()); System.out.println(notExistFile.isFile()); System.out.println(notExistFile.exists()); System.out.println(notExistFile.canRead()); System.out.println(notExistFile.canWrite()); System.out.println(notExistFile.isHidden()); } /** * false * true * true * true * true * false * ------------------------ * false * false * false * false * false * false */ /** * File类的创建删除文件/文件夹 * * @throws FileNotFoundException */ @Test public void test6() throws IOException { //创建删除文件 File file = new File("create-file.txt"); if (!file.exists()) { boolean flag = file.createNewFile(); if (flag) { System.out.println("创建文件成功"); } } else { boolean delete = file.delete(); if (delete) { System.out.println("删除文件成功"); } } //创建删除文件夹 File file2 = new File("create-dir"); if (!file2.exists()) { boolean flag = file2.mkdir(); if (flag) { System.out.println("创建文件夹成功"); } } else { boolean delete = file2.delete(); if (delete) { System.out.println("删除文件夹成功"); } } //创建删除多级文件夹 File file3 = new File("create-dir1/sub-dir1"); if (!file3.exists()) { //mkdirs可以递归创建文件夹,mkdir只能创建一级文件夹,如果有多级则创建不成功 boolean flag = file3.mkdirs(); if (flag) { System.out.println("创建文件夹成功"); } } else { boolean delete = file3.delete(); if (delete) { System.out.println("删除文件夹成功"); } } //删除多级文件夹,只能删除叶子节点的文件或文件夹,不能级联删除 //要想删除成功,被删除的文件夹下不能有子文件夹或者文件,如果是文件则文件要存在。 // File file4 = new File("create-dir1"); // System.out.println(file4.delete());//false }
I/O是指Input/Output(输入流/输出流)的意思,用来处理设备之间的数据传输。
输入输出流的划分是个相对的概念,我们在操作选择输入输出流是站在程序或者说内存的角度上看流属于输入还是输出。
我们应该站在内存的角度上去看流,读到内存中要找输入流,从内存中读到磁盘或者其他网络端叫输出流。
注意:文本文件操作读取输入流后展示(即在内存层面去读时)时要使用字符流操作,避免会有乱码的情况。当然如果只是读取数据并写入到文件中,则都可以用。而非文本文件即使没有在内存层面去读,直接写入硬盘,也不能用字符流处理,否则文件会打开失败。
public class FileReaderWriterTest { /** * 通过字符输入流读取文件数据打印到控制台 */ @Test public void test1() { //注意,一开始写代码时可以先抛出异常,等后面整理时再针对性try-catch处理 //1、实例化要操作的文件对象 FileReader fr = null; try { //如果读取的文件不存在会报文件未找到异常 File file = new File("new-io.txt"); //2、创建具体的流 fr = new FileReader(file); //3、数据的读入/写出 //从输入流中读取数据的下一个字节,没有返回-1 int data; while ((data = fr.read()) != -1) { //强转为字符 System.out.print((char) data); } } catch (IOException e) { e.printStackTrace(); } finally { //在关闭流时都要先判断字符输入流是否不为空 if (fr != null) { //关闭流 try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 通过字符输入流读取文件数据打印到控制台-加缓充 */ @Test public void test2() { //注意,一开始写代码时可以先抛出异常,等后面整理时再针对性try-catch处理 //1、实例化要操作的文件对象 FileReader fr = null; try { //如果读取的文件不存在会报文件未找到异常 File file = new File("new-io.txt"); //2、创建具体的流 fr = new FileReader(file); //3、数据的读入/写出 //从输入流中读取数据的下一个字节,没有返回-1 int len; char[] cbuff = new char[1024]; //一次读取多个可以提供效率,len是每次读取到cbuff数组中的个数,没有则返回-1 while ((len = fr.read(cbuff)) != -1) { //注意长度是len而不是数组cbuff的长度 //接收方式1: System.out.print(new String(cbuff, 0, len)); //接收方式2: /*for (int i = 0; i < len; i++) { System.out.print(cbuff[i]); }*/ } } catch (IOException e) { e.printStackTrace(); } finally { //在关闭流时都要先判断字符输入流是否不为空 if (fr != null) { //关闭流 try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 从内存中通过字符输出流写文件到硬盘中 * 输出操作的文件可以不存在,不存在时会自动创建此文件。 * 创建字符输出流时会有个append参数,默认是false,表示如果文件存在则覆盖 * 如果设置append参数=true,表示如果文件存在则会追加数据在文件里的末尾。 */ @Test public void test3() { FileWriter fw = null; try { //1、实例化要操作的文件对象 File file = new File("out-io.txt"); //2、创建具体的流 //FileOutputStream(File file, boolean append) append=false表示覆盖,true表示在文件末尾追加 fw = new FileWriter(file); //3、数据的写出 //直接写字符串,\n表示换行符 fw.write("everybody wants to rule the world!\n"); //也可以写字符数组 fw.write("不是哦,我只是个良民,活着就好!".toCharArray()); } catch (IOException e) { e.printStackTrace(); } finally { if (fw != null) { //4、关闭流资源 try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 读取硬盘中的文件到新文件中(复制)-字符流版 */ @Test public void test5() { FileReader fr = null; FileWriter fw = null; try { //1、实例化要操作的读入/写出文件对象 File srcFile = new File("new-io.txt"); File destFile = new File("new-io-copy.txt"); //2、创建输入流和输出流 fr = new FileReader(srcFile); fw = new FileWriter(destFile); //3、数据的读入和写出操作 int len; char[] buff = new char[1024]; while ((len = fr.read(buff)) != -1) { //注意要读多少个写出多少长度len fw.write(buff, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4、关闭流资源 if (fw != null) { try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } if (fr != null) { try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
public class FileInOutPutStreamTest { /** * 读取硬盘中的文件到新文件中(复制)-字节流版 */ @Test public void test() { copyFile("是大臣.jpg", "是大臣-copy.jpg"); } public void copyFile(String srcPath, String destPath) { FileInputStream fis = null; FileOutputStream fos = null; try { //1、实例化要操作的读入/写出文件对象 File srcFile = new File(srcPath); File destFile = new File(destPath); // File srcFile = new File("new-io.txt"); // File destFile = new File("new-io-copy.txt"); //2、创建输入流和输出流 fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); //3、数据的读入和写出操作 int len; byte[] buff = new byte[1024]; while ((len = fis.read(buff)) != -1) { //注意要读多少个写出多少长度len fos.write(buff, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4、关闭流资源 if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
处理流就是套接在已有流的基础上的流。
作用:提高流的读写速度。
原因:内部提供了一个默认8K的缓冲区。缓冲区大小我们可以在构造器中指定大小。
public class BufferedTest { /** * 使用缓存流进行复制 */ @Test public void test1() { //971M耗时1444ms 测试后如果指定的buff缓冲区越大理论上越好,因为顺序写速度更快 long start = System.currentTimeMillis(); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //1、实例化要操作的读入/写出文件对象 File srcFile = new File("E:/mv/[电影天堂www.dygod.com]倩女幽魂3:道道道BD国语中字.rmvb"); File destFile = new File("nxq.rmvb"); //2.1、创建输入流和输出流 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //2.1、创建缓存流 bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos, 8192);//1444ms // bos = new BufferedOutputStream(fos, 8192 / 2);//1952ms // bos = new BufferedOutputStream(fos, 8192 * 2);//1202ms // bos = new BufferedOutputStream(fos, 8192 * 8);//1101ms //3、数据的读入和写出操作 byte[] buffer = new byte[1024]; int len; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); //强制刷新缓冲区,会把缓冲区的数据刷新到磁盘中 // bos.flush(); } long end = System.currentTimeMillis(); System.out.println(end - start); } catch (IOException e) { e.printStackTrace(); } finally { //4、关闭流资源 关闭原则,先开启的后关闭,关闭外层包装流时内层流也会关闭,因此就不需要另外关闭 if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 使用缓存字符流进行文本复制 */ @Test public void test2() { //971M耗时1444ms 测试后如果指定的buff缓冲区越大理论上越好,因为顺序写速度更快 long start = System.currentTimeMillis(); BufferedReader br = null; BufferedWriter bw = null; try { //1、实例化要操作的读入/写出文件对象 //2.1、创建输入流和输出流 //2.1、创建缓存流 br = new BufferedReader(new FileReader(new File("new-io.txt"))); bw = new BufferedWriter(new FileWriter(new File("new-io-copy3.txt"))); //3、数据的读入和写出操作 //字符流读写的是字符,所以用字符容器 //方式一:使用char数组 /* char[] buffer = new char[1024]; int len; while ((len = br.read(buffer)) != -1) { bw.write(buffer, 0, len); //强制刷新缓冲区,会把缓冲区的数据刷新到磁盘中 // bw.flush(); }*/ //方式二:使用String String data; while ((data = br.readLine()) != null) { // bw.write(data+"\n"); //如果没有换号符,则会写在一起 bw.write(data); bw.newLine(); } long end = System.currentTimeMillis(); System.out.println(end - start); } catch (IOException e) { e.printStackTrace(); } finally { //4、关闭流资源 if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (bw != null) { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
转换流属于字符流,看流的归属看后缀。
InputStreamReader将字节流转换成字符流,并解码(字节、字节数组--->字符、字符数组)。
OutputStreamWriter将字符流转换成字节流,并编码(字符、字符数组--->字节、字节数组)。
编码解码过程需要字符集进行处理。
ASCII:因为只要表示字母这些所有一个字节就够了。
GBK,UTF-8都兼容了ASCII码表,所有在把原本是UTF-8的文本解码GBK时对于英文的部分也不会有什么问题,但中文部分就会乱码。
GBK,GBK2312是通过首字符是0表示一个字节代码一个字符;首字符是1表示需要读取2个字节表示一个字符来规范编码的,即用最高位是1或0来表示两个字节或一个字节。
编码和解码。
public class TransferIOTest { /** * 转换流读文件打印 */ @Test public void test1() { //1、创建字节流对象 InputStreamReader isr = null; try { FileInputStream fis = new FileInputStream("new-io.txt"); //没有指定解码的字符集的话就使用默认的字符集 // InputStreamReader isr = new InputStreamReader(fis); //2、创建字符转换流 isr = new InputStreamReader(fis, "UTF-8"); //3、解码读取 char[] buff = new char[1024]; int len; while ((len = isr.read(buff)) != -1) { //因为我们使用了文件原本的UTF-8字符集编码格式,所有在打印时就不会出现解码出现乱码的问题。 System.out.println(new String(buff, 0, len)); } } catch (IOException e) { e.printStackTrace(); } finally { if (isr != null) { //4、关闭流资源 try { isr.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * hello,my io * 我要被强转了 * hello,my io * 我要被强转了 * hello,my io * 我要被强转了我要被强转了我要被强转了我要被强转了我要被强转了 */ /** * 转换流读UTF-8文件保存成GBK文件 */ @Test public void test2() { //1、创建字节流对象 InputStreamReader isr = null; OutputStreamWriter osr = null; try { FileInputStream fis = new FileInputStream("new-io.txt"); FileOutputStream fos = new FileOutputStream("new-io-gbk.txt"); //没有指定解码的字符集的话就使用默认的字符集 // InputStreamReader isr = new InputStreamReader(fis); //2、创建字符转换流 //写代码时必须要指定字符集格式 isr = new InputStreamReader(fis, "UTF-8"); osr = new OutputStreamWriter(fos, "GBK"); //3、解码读取 char[] buff = new char[1024]; int len; while ((len = isr.read(buff)) != -1) { osr.write(buff,0,len); } } catch (IOException e) { e.printStackTrace(); } finally { if (isr != null) { //4、关闭流资源 try { isr.close(); } catch (IOException e) { e.printStackTrace(); } } if (osr != null) { //4、关闭流资源 try { osr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
public class OtherTest { /** * 利用标准输入输出流从键盘中读取输入,转换成大写打印到控制台上 * 注意idea不支持使用@Test测试方法读取键盘的输入,所以要改用main方法 * * @param args */ public static void main(String[] args) { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(System.in)); String data = ""; while (true) { System.out.println("请输入:"); data = br.readLine(); if ("exit".equalsIgnoreCase(data)) { System.out.println("再见!"); break; } System.out.println(data.toUpperCase()); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 请输入: * hhhh * HHHH * 请输入: * exit * 再见! */ /** * 打印流 */ @Test public void test1() { PrintStream ps = null; try { //创建打印输出流,并设置自动刷新,默认是false,自动刷新当遇到换行符或者\n时会刷新输出缓冲区 ps = new PrintStream(new FileOutputStream(new File("test-print.txt")),true); //把标准输出流(打印到控制台改成我们文件),我们的log日志记录到文本中就是用的打印流PrintStream/PrintWriter System.setOut(ps); String str = "我就是来测试打印流的\n现在开始测试:abcedsakjfslkdjfdfskgjdfkg\nsdfsdfsdf\n结束"; System.out.println(str); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (ps != null) { ps.close(); } } } /** * 数据流:读取和写出8种基本数据类型和字符串 */ @Test public void test2() throws Exception { DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt")); dos.writeUTF("期望薪资"); dos.writeInt(36000); dos.writeBoolean(true); dos.flush(); dos.close(); DataInputStream dis = new DataInputStream(new FileInputStream("data.txt")); //注意读取数据的时候要按照写入的顺序读,否则会报错 System.out.println(dis.readUTF()); System.out.println(dis.readInt()); System.out.println(dis.readBoolean()); dis.close(); } }
序列化**:把内存中的对象转换为二进制流。这样便可以将二进制流持久化到磁盘或者传输到另一个网络节点上。
反序列化:将二进制流还原成Java对象。
ublic class ObjectInputOutputStreamTest { /** * 对象序列化 * * @throws Exception */ @Test public void test1() throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt")); oos.writeObject(new Person("张三", 30, new Address("紫禁城1号"))); oos.writeObject(new String("我是艾米")); oos.flush(); oos.close(); } /** * 对象反序列化 * * @throws Exception */ @Test public void test2() throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt")); //需按照写入的对象顺序读取,否则会报错 Person person = (Person) ois.readObject(); String str = (String) ois.readObject(); System.out.println(person); System.out.println(str); ois.close(); } /** * Person(name=张三, age=30, address=Address(location=紫禁城1号)) * 我是艾米 */ } /** * 对象可序列化需满足3个条件: * 对象对应的类需要实现Serializable接口 * 需定义一个全局常量serialVersionUID * 对象内的所有属性也必须是可序列化的,比如自定义的Address类,基本数据类型都是可序列号的。 */ @Data @AllArgsConstructor @NoArgsConstructor public class Person implements Serializable { private static final long serialVersionUID = -6849344724054667710L; private String name; private int age; private Address address; } @Data @AllArgsConstructor @NoArgsConstructor public class Address implements Serializable { private static final long serialVersionUID = -684934470754667710L; private String location; }
public class RandomAccessFileTest { /** * 随机存取文件-读文件写到新的文件中 */ @Test public void test1() { RandomAccessFile read = null; RandomAccessFile write = null; try { //只读 read = new RandomAccessFile(new File("new-io.txt"), "r"); //可读可写 write = new RandomAccessFile(new File("test.txt"), "rw"); byte[] buff = new byte[1024]; int len; while ((len = read.read(buff)) != -1) { write.write(buff, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { if (read != null) { try { read.close(); } catch (IOException e) { e.printStackTrace(); } } if (write != null) { try { write.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 使用RandomAccessFile实现数据的插入效果 */ @Test public void test2() throws Exception { //可读可写 RandomAccessFile raf = new RandomAccessFile(new File("test.txt"), "rw"); //将指针调到角标为3的位置,0开始。 raf.seek(3); //保存角标3后的数据,然后再实现插入,最后再把角标3后位置的数据继续追加进来 //用字节数组输出流来保存数据避免乱码 ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buff = new byte[1024]; int len; while ((len = raf.read(buff)) != -1) { baos.write(buff, 0, len); } //调回要插入位置的指针 raf.seek(3); raf.write("哈哈哈我插入进来了".getBytes()); raf.write(baos.toString().getBytes()); raf.close(); baos.close(); } }
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
public class CommonsIOTest { @Test public void test() throws IOException { File srcFile = new File("是大臣.jpg"); File destFile = new File("是大臣-copy3.jpg"); FileUtils.copyFile(srcFile, destFile); } }
Java入门视频教程
577-617