手记

Java IO流(1) - 文件编码 & 常用API & RandomAccessFile类

文件编码

idea查看项目的编码:File -> Setting -> Editor -> File Encodings,其中有Global Encoding(全局编码),Project Encoding(项目编码)。

 public class EncodeDemo {
     public static void main(String[] args) throws UnsupportedEncodingException {
         String str = "学习io流";
         byte[] b1 = str.getBytes();// 转换成字节序列用的是项目默认的编码
         System.out.println("b1的编码为:(编码集为项目设置编码)");
         for (byte b : b1) {
             // toHexString()函数:把字节自动转换成了int类型,以16进制的方式显示
             System.out.print(Integer.toHexString(b & 0xff)+" ");
         }
         System.out.println("\n b2的编码为:(编码集为GBK)");
         byte[] b2 = str.getBytes("GBK");
         for (byte b : b2) {
             System.out.print(Integer.toHexString(b & 0xff) + " ");
         }
         System.out.println("\n b3的编码为:(编码集为utf-8)");
         byte[] b3 = str.getBytes(StandardCharsets.UTF_8);
         for (byte b : b3) {
             System.out.print(Integer.toHexString(b & 0xff) + " ");
         }
         System.out.println("\n b4的编码为:(编码集为utf-16be)");
         byte[] b4 = str.getBytes(StandardCharsets.UTF_16BE);
         for (byte b : b4) {
             System.out.print(Integer.toHexString(b & 0xff) + " ");
         }
         System.out.println();
         /**
          * 由此可见:
          *  GBK编码中文占2个字节,英文占1个字节
          *  utf-8编码中文占3个字节,英文占1个字节
          *  utf-16be中文占2个字节,英文占2个字节
          *
          * Java是双字节编码(utf-16be编码)
          *
          * 当你的字节序列是某种编码时,想把字节序列变成字符串,也需要这种编码方式,
          * 否则会出现乱码
          */
         String str1 = new String(b4);
         System.out.println(str1);
         String str2 = new String(b4, StandardCharsets.UTF_16BE);
         System.out.println(str2);
 
         /**
          * 文本文件就是字节序列,可以是任意编码的字节序列
          * 如果我们在中文机器(Windows)上直接创建文本文件,那么该文本文件只认识ANSI编码
          */
     }
 }

输出结果:

 b1的编码为:(编码集为项目设置编码)
 e5 ad a6 e4 b9 a0 69 6f e6 b5 81 
  b2的编码为:(编码集为GBK)
 d1 a7 cf b0 69 6f c1 f7 
  b3的编码为:(编码集为utf-8)
 e5 ad a6 e4 b9 a0 69 6f e6 b5 81 
  b4的编码为:(编码集为utf-16be)
 5b 66 4e 60 0 69 0 6f 6d 41 
 [fN` i omA
 学习io流

File类常用API介绍

java.io.File类用于表示文件(目录)。

File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问。

 public class FileDemo {
     public static void main(String[] args) {
         // 了解构造函数的情况,可以在File上使用快捷键:Alt+/
         File f1 = new File("F:\\000学习资料\\01JavaWeb笔记");
         System.out.println(f1);
         System.out.println("判断该文件夹(目录)是否存在:"+f1.exists());
         File f2 = new File("F:\\000学习资料\\01JavaWeb笔记\\io输入输出");
         if (!f2.exists()) {
             f2.mkdir(); //表示如果文件夹(目录)不存在则创建单级目录
 //            f2.mkdirs();//可以创建多级目录
             
         } else {
             f2.delete(); //如果存在则删除
         }
         // File.separator 在此路径结束后追加分隔符( \ )
         File f3 = new File("F:\\000学习资料\\01JavaWeb笔记", File.separator);
         System.out.println(f3);
         // 判断是否是一个目录,如果是则返回true,如果不是目录或者不存在则返回false
         System.out.println(f3.isDirectory());
         // 判断是否是一个文件,(同上)
         System.out.println(f3.isFile());
 //        File f4 = new File("F:\\000学习资料\\01JavaWeb笔记\\io.txt");
         // 与上面的方法实现功能相同,只是该方法的逗号前面指定父级,后面指定子级
         File f4 = new File("F:\\000学习资料\\01JavaWeb笔记","io.txt");
         if (!f4.exists()) { //判断该文件是否存在
             try {
                 f4.createNewFile(); //如果不存在则创建该文本文件
             } catch (IOException e) {
                 e.printStackTrace();
             }
         } else {
             f4.delete(); //如果存在则删除
         }
 
         // 常用的file对象API
         System.out.println("f1的内容:"+f1.toString());
         System.out.println("f1的绝对路径:"+f1.getAbsoluteFile());
         System.out.println("f1的名字:"+f1.getName());
         System.out.println("f2的名字:"+f2.getName());
         System.out.println("获取f2的父级:"+f2.getParent());
         System.out.println("获取f2的父级文件:"+f2.getParentFile());
     }
 }

输出结果:

 F:\000学习资料\01JavaWeb笔记
 判断该文件夹(目录)是否存在:true
 F:\000学习资料\01JavaWeb笔记\
 true
 false
 f1的内容:F:\000学习资料\01JavaWeb笔记
 f1的绝对路径:F:\000学习资料\01JavaWeb笔记
 f1的名字:01JavaWeb笔记
 f2的名字:io输入输出
 获取f2的父级:F:\000学习资料\01JavaWeb笔记
 获取f2的父级文件:F:\000学习资料\01JavaWeb笔记

遍历目录

写一个FileUtils工具类,列出File的一些常用操作,比如过滤、遍历等操作,以方便项目以后的使用:

 public class FileUtils {
     /**
      * 列出指定目录下(包括其子目录)的所有文件
      * @param dir
      * @throws IOException
      */
     public static void listDirectory(File dir) throws IOException {
         if (!dir.exists()) {
             throw new IllegalArgumentException("目录"+dir+"不存在~");
         }
         if (!dir.isDirectory()) {
             throw new IllegalArgumentException(dir+"不是目录~");
         }
         // dir.list():返回字符串数组,直接子目录的名称,不包括子目录下的文件
 //        String[] fileNames = dir.list();
 //        for (String fileName : fileNames) {
 //            System.out.println(dir+"\\"+fileName);
 //        }
 
         // 如果要遍历子目录下的文件,就需要构造File对象做递归操作,File提供了直接返回file对象的API
         File[] files = dir.listFiles();
 //        for (File file : files) {
 //            System.out.println(file);// 返回的是直接子目录(文件)的抽象
 //        }
         if (files != null && files.length > 0) {
             for (File file : files) {
                 if (file.isDirectory()) {
                     // 递归
                     listDirectory(file);
                 }
                 System.out.println(file);
             }
         }
     }
 }

遍历目录测试类:

 public class ErgodicTest {
     public static void main(String[] args) throws IOException {
         FileUtils.listDirectory(new File("F:\\000学习资料\\01JavaWeb笔记\\04输入输出流"));
     }
 }

输出结果:

 F:\000学习资料\01JavaWeb笔记\04输入输出流\0704.md
 F:\000学习资料\01JavaWeb笔记\04输入输出流\io\io.txt
 F:\000学习资料\01JavaWeb笔记\04输入输出流\io

RandomAccessFile类

RandomAccessFile是Java提供的对文件内容的访问,既可以读文件,也可以写文件。支持随机访问文件,可以访问文件的任意位置。

(1)Java文件模型:

在硬盘上的文件是用字节存储的,是数据的集合。

(2)打开文件(四种模式):


模式说明
r以只读的方式打开文本,也就意味着不能用write来操作文件
rw读操作和写操作都是允许的
rws每当进行写操作,同步的刷新到磁盘,刷新内容和元数据
rwd每当进行写操作,同步的刷新到磁盘,刷新内容
 RandomAccessFile raf = new RandomAccessFile(file, "rw");

文件指针:打开文件时指针为0(pointer = 0;).

(3)写方法

raf.write(type) --> 每次只写一个字节(后8位,如果要写一个int类型数据,则需要写4次),同时指针指向下一个位置,准备下一次写入

(4)读方法

int b = raf.read(); --> 读一个字节

(5)文件读写完成后一定要关闭,否则会造成资源浪费.

 public class RafDemo {
     public static void main(String[] args) throws IOException {
         File demo = new File("demo");
         if (!demo.exists()) {
             demo.mkdir();
             File file = new File("raf.txt");
             if (!file.exists()) {
                 file.createNewFile();
             }
             // 指定随机读写操作
             RandomAccessFile rw = new RandomAccessFile(file, "rw");
             // 指针的位置
             System.out.println(rw.getFilePointer());
             rw.writeBytes("ABC");
             System.out.println(rw.getFilePointer());
             rw.write('B');
             int n = 0x7fffffff;
             // 用write方法每次只能写一个字节(8位),如果要把n写进去则需要写4次
             rw.write(n >>> 24); //右移24位,把高8位写进去
             rw.write(n >>> 16); //右移16位
             rw.write(n >>> 8); //右移8位
             rw.write(n);
             System.out.println(rw.getFilePointer());
             // 可以直接写一个int
             rw.writeInt(n); //其底层就是做了上面的操作
 
             String str = "中国";
             byte[] bs = str.getBytes();
             rw.write(bs);
             System.out.println(rw.length());// 一个中文占两个字节长度
 
             // 读文件,必须把指针移到头部
             rw.seek(0);
             // 一次性读取,把文件中的内容都读到字节数组中
             byte[] buffer = new byte[(int) rw.length()];
             int len;
             rw.read(buffer);
             System.out.println(Arrays.toString(buffer));
 
             for (byte b : buffer) {
                 System.out.print(Integer.toHexString(b & 0xff) + " ");
             }
             System.out.println();
 
             rw.seek(0);
             while ((len = rw.read(buffer)) != -1) {
                 System.out.println(new String(buffer, 0, len));
             }
 
             // 关闭资源
             rw.close();
         } else {
             demo.delete();
         }
     }
 }

输出结果:

 0
 3
 8
 18
 [65, 66, 67, 66, 127, -1, -1, -1, 127, -1, -1, -1, -28, -72, -83, -27, -101, -67]
 41 42 43 42 7f ff ff ff 7f ff ff ff e4 b8 ad e5 9b bd 
 ABCB•���•���中国

(中间用write分段写的int类型乱码了,不知道是咋回事。。如果有大佬看到希望能告知是怎么回事,谢谢~)


1人推荐
随时随地看视频
慕课网APP