java文件操作

java文件操作

  • 使用File类,常用API有:(如 new File("a/b/c.txt"))

    File类是不分文件还是文件夹的,两个都可以用来生成File对象。

    • getPath:得到的是初始化时的路径,即"a/b/c.txt"

    • getParentFile:得到上一层级File对象,即File("a/b")

    • getName:得到的是文件名,即"c.txt"

    • listFiles:得到的是File[]数组,即当前路径下所有文件/文件夹。list()得到的是Sting[]文件名数组

      // 使用FileFilter对listFiles()进行过滤,也可以替换为lambda表达式
      File[] files = dir.listFiles(pathname -> pathname.getPath().endsWith(".txt"));
      File[] files = dir.listFiles(new FileFilter() {
          @Override
          public boolean accept(File pathname) {
              return pathname.getPath().endsWith(".txt");  // 只要.txt后缀的文件
          }
      });
      
    • renameTo(参数是File对象):若原文件是存在的,则真的是会对原文件重命名,不存在也不报错

    • createNewFile:文件所在文件夹不存在会报错

    • isFile、isDirectory、getAbsolutePath、exists、mkdir、mkdirs(递归创建)、delete、deleteOnExit、canRead/canWrite/canExecute、setReadOnly、getTotalSpace、getUsableSpace、toURI、toPath等

  • 文件复制/移动

    文件的移动在复制后调用delete即可,或者用java7的NIO包中的Files类的move方法

    • 1、FileStream文件二进制流;2、使用nio的FileChannel的transferFrom方法,较FileStream方式高效;3、使用java7的Files类;4、使用Apache Commons IO提供拷贝文件方法在其FileUtils类,本质还是使用了NIO的FileChannel

      // 拷贝单个文件:方式1:FileStream文件二进制流
      try {
          is = new FileInputStream(inPath);
          os = new FileOutputStream(outPath);
          byte[] b = new byte[1024];
          while (is.read(b) != -1) {
              os.write(b);
          }
      } catch (Exception e) {e.printStackTrace();}
      
      // 拷贝单个文件:方式2:使用nio的FileChannel的transferFrom方法,较FileStream方式高效
      try {
          inputChannel = new FileInputStream(inPath).getChannel();
          outputChannel = new FileOutputStream(outPath).getChannel();
          outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
      } catch (Exception e) {}
      
      // 拷贝单个文件:方式3:使用java7的nio包新增的Files类
      try {
          Files.copy(new File(inPath).toPath(), new File(outPath).toPath());
          return true;
      } catch (IOException e) {}
      
      // 拷贝单个文件:方式4:使用Apache Commons IO提供拷贝文件方法在其FileUtils类,本质还是使用了NIO的FileChannel
      // public void copyFileUsingApacheCommonsIO(File source, File dest) {
      //     FileUtils.copyFile(source, dest);
      // }
      
  • 文件压缩和解压

    • Apache Commons Compress

    • zip4j

    • 自定义压缩解压,利用nio包优化字节流传输效率。

      自己写则使用ZipOutputStream,每次用流写入前都要putNextEntry放入一个入口路径。

      直接缓冲区:直接缓冲区不在JVM中开辟,由操作系统决定何时写入。当线程处于内核空间称之为内核态,处于用户空间则属于用户态。java的线程操作java内置数组,内置数组在用户空间属于用户态,也就是:操作系统磁盘IO操作要先经过内核空间,再传递给用户空间,还需要和内核空间交互,因此速度较。若使用直接缓冲区,开辟的是JVM外的直接物理空间,操作系统IO直接由内核写入直接缓冲区,不必再传递给jvm的内存空间,操作完毕再通知java,因此速度较

      ​ 但直接缓冲区也有缺点:因为不在JVM的内存模型中,所以不安全;消耗多;JVM对数据的管理权限下降

      • 利用非直接缓冲区,即java的字节数组作为中间人,写入数据。若不用BufferedInputStream字节数组,会慢很多倍!
      • 利用FileChannel的直接缓冲区,效率更高。
        • 利用FileChannel.transferTo,直接连通2个channel通过直接换乘写入。
        • 利用内存映射文件MappedByteBuffer,NIO新特性。
      // 方式1:利用非直接缓冲区,即java的字节数组作为中间人,写入数据。若不用BufferedInputStream字节数组,会慢很多倍!
      private void zipSingleFileUsingZipStream(File file, ZipOutputStream zos) {
          try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
              byte[] b = new byte[bufferSize];
              while (bis.read(b) != -1) zos.write(b);
          } catch (Exception ignored) {}
      }
      
      // 利用FileChannel的直接缓冲区,直接缓冲区不在JVM中开辟,由操作系统决定何时写入。效率更高
      private void zipSingleFileUsingChannel(File file, WritableByteChannel zoc) {
          try (FileChannel fileInChannel = new FileInputStream(file).getChannel()) {
              // 方式2:利用FileChannel.transferTo,直接连通2个channel通过直接换乘写入。
              fileInChannel.transferTo(0, fileInChannel.size(), zoc);
      
              // 方式3:利用内存映射文件,NIO新特性。也是开辟直接缓冲区,和方式2效率差不多。
              // MappedByteBuffer mbb = fileInChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileInChannel.size());
              // zoc.write(mbb);
          } catch (Exception ignored) {}
      }
      
  • 操作excel

    • POI
      • 导出步骤? 创建工作簿对象,若是小表XSSFWorkbook就行,若是大表用SXSSFWorkbook(支持百万级,原理就是利用缓冲区,达到指定大小就自动刷新写入磁盘,避免内存溢出);创建sheet对象,设置行、列数等其他样式;创建标题单元格(即表头);写入数据时,每次换行调用createRow(),每次写单元格就调用createCell()
      • 导入步骤?和导出类似,使用ExcelReader对象读取excel,使用getRow和getCell读取行和单元格。如果要读大表,普通读取会全表扫描进内存,应该使用SAX技术(一边加载一边解析),方法是修改SheetContentsHandler接口源码或者继承DefaultHandler(推荐),使用DefaultHandler就是事件驱动,重写end/startElement方法
    • JXL
posted @ 2021-04-22 23:25  i%2  阅读(60)  评论(0)    收藏  举报