100G的文件如何读取 - 第306篇
一、内存读取法:简单明了,不玩阴的
此方法的思路很简单,就是把文件直接读取到内存中,然后进行操作。
1.1 方法一:使用java.nio.file.Files读取文本文件
使用Files类将文件的所有内容读入字节数组。Files类还有一个方法可以读取所有行到字符串列表。Files类是在Java 7中引入的,如果想加载所有文件内容,使用这个类是比较适合的。只有在处理小文件并且需要加载所有文件内容到内存中时才应使用此方法。
- public static void readFileByFiles(String pathname) {
- Path path = Paths.get(pathname);
- try {
- /*
- * 使用readAllLines的时候,小文件可以很快读取.
- * 那么更大的文件,读取的肯定会爆了。
- */
- //List<String> lines = Files.readAllLines(path);
-
- byte[] bytes = Files.readAllBytes(path);
- String str = new String(bytes);
- System.out.println(str);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
对于小文件,轻松就可以读取进来;
对于大文件就会抛出如下异常:
或者是:
结论:小文件可以使用这种方式;读取大文件,不能使用。
二、IO逐行读取法:循序渐进,好舒服
2.1 方法二:使用java.io.FileReader类
可以使用FileReader获取BufferedReader,然后逐行读取文件,FileRead也有读取char的方法,当然这样的读取方式效率很低很低了。
- public static void readFileByFileReader(String pathname) {
- File file = new File(pathname);
- FileReader fileReader;
- BufferedReader bufferedReader;
- try {
- fileReader = new FileReader(file);
-
- bufferedReader = new BufferedReader(fileReader);
- String line;
- StringBuffer buffer = new StringBuffer();
- while((line = bufferedReader.readLine()) != null){
- // 一行一行地处理...
- //System.out.println(line);
- //处理字符串,并不会将字符串保存真正保存到内存中
- // 这里简单模拟下处理操作.
- buffer.append(line.substring(0,1));
- }
- System.out.println("buffer.length:"+buffer.length());
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- //TODO close处理.
- }
-
- }
对于大文件可以逐行读取,没啥问题,测试了下:3.46G 耗时:11秒
注意:这里本质是使用了BufferedReader的缓冲,如果是使用的fileReader读取char的方式,那么时间会更久。
2.2方法三:使用java.io.BufferedReader
如果想逐行读取文件并对它们进行处理,那么BufferedReader是非常合适的。它适用于处理大文件,也支持编码。BufferedReader是同步的,因此可以安全地从多个线程完成对BufferedReader的读取操作。BufferedReader的默认缓冲区大小为:8KB。
- public static void readFileByBufferedReader(String pathname) {
-
- File file = new File(pathname);
- BufferedReader reader = null;
- FileInputStream fileInputStream = null;
- InputStreamReader inputStreamReader = null;
- try {
- //使用BufferedReader,每次读入1M数据.减少IO.如:
- fileInputStream = new FileInputStream(file);
- inputStreamReader = new InputStreamReader(fileInputStream, Charset.defaultCharset());
- reader = new BufferedReader(inputStreamReader,1*1024*1024);
- String tempString = null;
- StringBuffer buffer = new StringBuffer();
- while( (tempString = reader.readLine()) != null) {
- //System.out.println(tempString);
- //处理字符串,并不会将字符串保存真正保存到内存中
- // 这里简单模拟下处理操作.
- buffer.append(tempString.substring(0,1));
- }
- System.out.println("buffer.length:"+buffer.length());
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- //TODO close处理
- }
-
- }
逐行读取,可以处理大文件,测试3.46G 耗时:10秒
2.3方法四:使用Scanner读取文本文件
如果要逐行读取文件或基于某些java正则表达式读取文件,则可使用Scanner类。
Scanner类使用分隔符模式将其输入分解为标记,分隔符模式默认匹配空格。然后可以使用各种下一种方法将得到的标记转换成不同类型的值。Scanner类不同步,因此不是线程安全的。
- public static void readFileByScanner(String filePath) {
- FileInputStream inputStream = null;
- Scanner sc = null;
- try {
- inputStream = new FileInputStream(filePath);
- sc = new Scanner(inputStream, "UTF-8");
- StringBuffer buffer = new StringBuffer();
- while (sc.hasNextLine()) {
- String line = sc.nextLine();
- //System.out.println(line);
- //处理字符串,并不会将字符串保存真正保存到内存中
- // 这里简单模拟下处理操作.
- buffer.append(line.substring(0,1));
- }
- System.out.println("buffer.length:"+buffer.length());
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- //TODO close处理
- }
- }
逐行处理,可以处理大文件,测试3.46G 耗时:57秒
2.4 方法五:使用RandomAccessFile读取文本文件
Java中的RandomAccessFile提供了对文件的读写功能。RandomAccessFile 虽然属于java.io下的类,但它不是InputStream或者OutputStream的子类;它也不同于FileInputStream和FileOutputStream。 FileInputStream 只能对文件进行读操作,而FileOutputStream 只能对文件进行写操作;但是RandomAccessFile 与输入流和输出流不同之处就是RandomAccessFile可以访问文件的任意地方同时支持文件的读和写,并且它支持随机访问。RandomAccessFile包含InputStream的三个read方法,也包含OutputStream的三个write方法。同时RandomAccessFile还包含一系列的readXxx和writeXxx方法完成输入输出。
- public static void readFileByRandomAccessFile(String pathname) {
- RandomAccessFile randomAccessFile = null;
- String str;
- try {
- randomAccessFile = new RandomAccessFile(pathname, "r");
- StringBuffer buffer = new StringBuffer();
- while ((str = randomAccessFile.readLine()) != null) {
- //System.out.println(str);
- //处理字符串,并不会将字符串保存真正保存到内存中
- // 这里简单模拟下处理操作.
- buffer.append(str.substring(0,1));
- }
- System.out.println("buffer.length:"+buffer.length());
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- //TODO close处理
- }
- }
逐行读取,可以读取大文件,测试3.46G 耗时:很长...
三、NIO逐行读取法:新的姿势,新的体验
3.1 方法五:使用FileChannel读取文本
顾名思义,FileChannel就是连接到文件的Channel。使用FileChannel,你可以读取文件数据,以及往文件里面写入数据。Java NIO的FileChannel是使用标准Java IO读取文件的一种替代方案。
- public static void readFileFileChannel(String pathname) {
- File file = new File(pathname);
- FileInputStream fileInputStream = null;
-
- try {
- fileInputStream = new FileInputStream(file);
- FileChannel fileChannel = fileInputStream.getChannel();
-
- int capacity = 1*1024*1024;//1M
- ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);
- StringBuffer buffer = new StringBuffer();
- while( fileChannel.read(byteBuffer) != -1) {
- //读取后,将位置置为0,将limit置为容量, 以备下次读入到字节缓冲中,从0开始存储
- byteBuffer.clear();
- byte[] bytes = byteBuffer.array();
- String str = new String(bytes);
- //System.out.println(str);
- //处理字符串,并不会将字符串保存真正保存到内存中
- // 这里简单模拟下处理操作.
- buffer.append(str.substring(0,1));
- }
- System.out.println("buffer.length:"+buffer.length());
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }finally {
- //TODO close处理.
- }
-
- }
逐行读取,可以读取大文件,测试3.46G 耗时:3秒,测试6.5G 耗时:6秒
四、悟纤小结
小结下:
(1)java底层天然支持大文件的读取。
(2)常用的方式就是BufferedReader、FileChannel,FileChannel已经是很快了,测试3.46G 耗时:3秒,测试6.5G 耗时:6秒,测试13G 耗时15秒,那么130G,那么也就150秒左右了。
(3)NIO在大文件上的操作很占优势。(NIO为什么会这么快呢?)
- 我就是我,是颜色不一样的烟火。
- 我就是我,是与众不同的小苹果。
购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287