• 三种访问文件的方式


    标准IO,带缓冲的标准IO,内存映射等在Java中的实现:

      1 package com.mesopotamia.test;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.ByteArrayInputStream;
      5 import java.io.File;
      6 import java.io.FileNotFoundException;
      7 import java.io.FileReader;
      8 import java.io.IOException;
      9 import java.io.RandomAccessFile;
     10 import java.nio.ByteBuffer;
     11 import java.nio.MappedByteBuffer;
     12 import java.nio.channels.FileChannel;
     13 import java.util.Scanner;
     14 
     15 import org.apache.log4j.Logger;
     16 /*
     17  * 原文学习请加微信订阅号:it_pupil
     18  * **/
     19 public class FileRead {
     20     private static Logger logger = Logger.getLogger(FileRead.class); 
     21     public static void main(String args[]) throws FileNotFoundException{
     22         String path = "C:" + File.separator + "test" + File.separator + "Alice.txt";  
     23         readFile3(path);
     24     }
     25     
     26     public static void readFile(String path) throws FileNotFoundException {
     27         long start = System.currentTimeMillis();//开始时间
     28         int bufSize = 1024;//1K缓冲区
     29         File fin = new File(path); 
     30         /*
     31          * 通道就是为操作文件而建立的一个连接。(读写文件、内存映射等)
     32          * 此处的getChannel()可以获取通道;
     33          * 用FileChannel.open(filename)也可以创建一个通道。
     34          * "r"表示只读。
     35          * 
     36          * RandomAccessFile是独立与I/O流家族的类,其父类是Object。
     37          * 该类因为有个指针可以挪动,所以,可以从任意位置开始读取文件数据。
     38          * **/
     39         FileChannel fcin = new RandomAccessFile(fin, "r").getChannel();
     40         //给字节缓冲区分配大小
     41         ByteBuffer rBuffer = ByteBuffer.allocate(bufSize);                        
     42         String enterStr = "
    ";
     43         try {
     44             byte[] bs = new byte[bufSize];
     45             String tempString = null;
     46             while (fcin.read(rBuffer) != -1) {//每次读1k到缓冲区
     47                 int rSize = rBuffer.position();//记录缓冲区当前位置
     48                 rBuffer.rewind();//位置归零,标记取消,方便下次循环重新读入缓冲区。
     49                 rBuffer.get(bs);//将缓冲区数据读到字节数组中
     50                 rBuffer.clear();//清除缓冲
     51                 /*
     52                  * 用默认编码将指定字节数组的数据构造成一个字符串
     53                  * bs:指定的字节数组,0:数组起始位置;rSize:数组结束位置
     54                  * */
     55                 tempString = new String(bs, 0, rSize);
     56                 int fromIndex = 0;//每次读的开始位置
     57                 int endIndex = 0;//每次读的结束位置
     58                 //按行读String数据
     59                 while ((endIndex = tempString.indexOf(enterStr, fromIndex)) != -1) {
     60                     String line = tempString.substring(fromIndex, endIndex);//转换一行            
     61                     System.out.print(line);                     
     62                     fromIndex = endIndex + 1;
     63                 }
     64             }
     65             long end = System.currentTimeMillis();//结束时间
     66             System.out.println("传统IO读取数据,指定缓冲区大小,总共耗时:"+(end - start)+"ms");
     67 
     68         } catch (IOException e) {
     69             e.printStackTrace();
     70         }
     71     }
     72     
     73     public static void readFile1(String path) { 
     74         long start = System.currentTimeMillis();//开始时间
     75         File file = new File(path);  
     76         if (file.isFile()) {  
     77             /*使用Reader家族,表示我要读字符数据了,
     78              *使用该家族中的BufferedReader,表示我要建立缓冲区读字符数据了。
     79              * */
     80             BufferedReader bufferedReader = null;  
     81             FileReader fileReader = null;  
     82             try {  
     83                 fileReader = new FileReader(file); 
     84                 //嵌套使用,装饰者模式,老生常谈。装饰者模式的使用,可以读前面小砖写的《从熏肉大饼到装饰者模式》
     85                 bufferedReader = new BufferedReader(fileReader);  
     86                 String line = bufferedReader.readLine();  
     87                 //一行一行读
     88                 while (line != null) { //按行读数据
     89                     System.out.println(line);  
     90                     line = bufferedReader.readLine();  
     91                 }  
     92             } catch (FileNotFoundException e) {  
     93                 e.printStackTrace();  
     94             } catch (IOException e) {  
     95                 e.printStackTrace();  
     96             } finally {  
     97                 //最后一定要关闭
     98                 try {  
     99                     fileReader.close();  
    100                     bufferedReader.close();  
    101                 } catch (IOException e) {  
    102                     e.printStackTrace();  
    103                 }  
    104                 long end = System.currentTimeMillis();//结束时间
    105                 System.out.println("传统IO读取数据,不指定缓冲区大小,总共耗时:"+(end - start)+"ms");
    106             }  
    107   
    108         }  
    109     } 
    110     
    111     public static void readFile3(String path) {
    112         long start = System.currentTimeMillis();//开始时间
    113         long fileLength = 0;  
    114         final int BUFFER_SIZE = 0x300000;// 3M的缓冲  
    115             File file = new File(path);  
    116             fileLength = file.length();  
    117             try {  
    118                 /*使用FileChannel.map方法直接把整个fileLength大小的文件映射到内存中**/
    119                 MappedByteBuffer inputBuffer = new RandomAccessFile(file, "r").getChannel()
    120                     .map(FileChannel.MapMode.READ_ONLY, 0, fileLength);// 读取大文件  
    121                 byte[] dst = new byte[BUFFER_SIZE];// 每次读出3M的内容
    122                 //每3M做一个循环,分段将inputBuffer的数据取出。
    123                 for (int offset = 0; offset < fileLength; offset += BUFFER_SIZE) {
    124                     //防止最后一段不够3M
    125                     if (fileLength - offset >= BUFFER_SIZE) {
    126                         //一个字节一个字节的取出来放到byte[]数组中。
    127                         for (int i = 0; i < BUFFER_SIZE; i++)  
    128                             dst[i] = inputBuffer.get(offset + i);  
    129                     } else {  
    130                         for (int i = 0; i < fileLength - offset; i++)  
    131                             dst[i] = inputBuffer.get(offset + i);  
    132                     }  
    133                     // 将得到的3M内容给Scanner,这里的XXX是指Scanner解析的分隔符。
    134                     Scanner scan = new Scanner(new ByteArrayInputStream(dst)).useDelimiter("XXX");  
    135                     //hasNext()所参照的token就是上面的XXX
    136                     while (scan.hasNext()) {  
    137                         // 这里为对读取文本解析的方法  
    138                         System.out.print(scan.next() + "XXX");  
    139                     }  
    140                     scan.close();  
    141                 }  
    142                 System.out.println();
    143                 long end = System.currentTimeMillis();//结束时间
    144                 System.out.println("NIO 内存映射读大文件,总共耗时:"+(end - start)+"ms");
    145             } catch (Exception e) {  
    146                 e.printStackTrace();  
    147             }  
    148     } 
    149 }

    内容来自:《磁盘IO的工作机制》,发布自微信订阅号:it_pupil

    《磁盘IO的工作机制》主要内容:

      内核空间与用户空间(以及数据在二者之间的转换);

      标准访问文件的方式(要同时经过内核空间、用户空间的双重拷贝)(局部性原理);

      带缓冲访问文件的方式;

      直接IO(避开内核缓冲区,适合在应用程序中管理缓存的系统,比如:数据库管理系统);

      内存映射(磁盘文件与用户空间的直接映射,减少拷贝数据的次数,适合大文件的读写。);

      阻塞与非阻塞,同步与异步的区分(非阻塞同步、非阻塞异步的介绍);

    订阅号二维码:

      

      

  • 相关阅读:
    在SplendidCRM中添加用户控件
    SPendidCRM:给HK的ImageInfoEntryEditView增加一个checkbox,用于判断特殊类型的PODS记录
    html button 跳转ASP.NET页面跳转技术总结
    让<li>不显示超出内容,显示... (编程方法和CSS方法)
    SplendidCRM Popup.aspx的hyperlink字段配置的易错点
    asp.net 个别页面URL参数出现中文乱码的解决方法
    解决:工具箱里边没了Dev控件
    DevControlgridview的属性说明 (转)
    DevControlgridview的属性说明 (转)
    VM如何设置U盘启动
  • 原文地址:https://www.cnblogs.com/mesopotamia/p/5844616.html
Copyright © 2020-2023  润新知